From b7e5ea196f2ee56afa955cb3e0f85a7514838151 Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 02:42:04 +0200
Subject: [PATCH 01/18] feat(agent-toolkit): Introduce @clerk/agent-toolkit
package
---
packages/agent-toolkit/LICENSE | 21 ++
packages/agent-toolkit/README.md | 230 +++++++++++++++
packages/agent-toolkit/package.json | 66 +++++
packages/agent-toolkit/src/ai-sdk/adapter.ts | 12 +
packages/agent-toolkit/src/ai-sdk/index.ts | 43 +++
packages/agent-toolkit/src/global.d.ts | 6 +
.../agent-toolkit/src/langchain/adapter.ts | 13 +
packages/agent-toolkit/src/langchain/index.ts | 48 ++++
.../agent-toolkit/src/lib/clerk-client.ts | 22 ++
packages/agent-toolkit/src/lib/clerk-tool.ts | 55 ++++
packages/agent-toolkit/src/lib/constants.ts | 5 +
.../src/lib/inject-session-claims.ts | 18 ++
packages/agent-toolkit/src/lib/tools/index.ts | 15 +
.../agent-toolkit/src/lib/tools/user-tools.ts | 52 ++++
packages/agent-toolkit/src/lib/types.ts | 26 ++
packages/agent-toolkit/src/lib/utils.ts | 66 +++++
packages/agent-toolkit/tsconfig.json | 19 ++
packages/agent-toolkit/tsconfig.test.json | 6 +
packages/agent-toolkit/tsup.config.ts | 23 ++
packages/backend/src/api/resources/User.ts | 10 +-
pnpm-lock.yaml | 263 +++++++++++++++++-
21 files changed, 1010 insertions(+), 9 deletions(-)
create mode 100644 packages/agent-toolkit/LICENSE
create mode 100644 packages/agent-toolkit/README.md
create mode 100644 packages/agent-toolkit/package.json
create mode 100644 packages/agent-toolkit/src/ai-sdk/adapter.ts
create mode 100644 packages/agent-toolkit/src/ai-sdk/index.ts
create mode 100644 packages/agent-toolkit/src/global.d.ts
create mode 100644 packages/agent-toolkit/src/langchain/adapter.ts
create mode 100644 packages/agent-toolkit/src/langchain/index.ts
create mode 100644 packages/agent-toolkit/src/lib/clerk-client.ts
create mode 100644 packages/agent-toolkit/src/lib/clerk-tool.ts
create mode 100644 packages/agent-toolkit/src/lib/constants.ts
create mode 100644 packages/agent-toolkit/src/lib/inject-session-claims.ts
create mode 100644 packages/agent-toolkit/src/lib/tools/index.ts
create mode 100644 packages/agent-toolkit/src/lib/tools/user-tools.ts
create mode 100644 packages/agent-toolkit/src/lib/types.ts
create mode 100644 packages/agent-toolkit/src/lib/utils.ts
create mode 100644 packages/agent-toolkit/tsconfig.json
create mode 100644 packages/agent-toolkit/tsconfig.test.json
create mode 100644 packages/agent-toolkit/tsup.config.ts
diff --git a/packages/agent-toolkit/LICENSE b/packages/agent-toolkit/LICENSE
new file mode 100644
index 00000000000..66914b6af7c
--- /dev/null
+++ b/packages/agent-toolkit/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Clerk, Inc.
+
+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/packages/agent-toolkit/README.md b/packages/agent-toolkit/README.md
new file mode 100644
index 00000000000..dddab065a8c
--- /dev/null
+++ b/packages/agent-toolkit/README.md
@@ -0,0 +1,230 @@
+
+
+
+
+
+
+
+
+
@clerk/agent-toolkit
+
+
+
+
+[](https://clerk.com/discord)
+[](https://clerk.com/docs?utm_source=github&utm_medium=clerk_agent_toolkit)
+[](https://twitter.com/intent/follow?screen_name=ClerkDev)
+
+[Changelog](https://github.com/clerk/javascript/blob/main/packages/agent-toolkit/CHANGELOG.md)
+·
+[Report a Bug](https://github.com/clerk/javascript/issues/new?assignees=&labels=needs-triage&projects=&template=BUG_REPORT.yml)
+·
+[Request a Feature](https://feedback.clerk.com/roadmap)
+·
+[Get Help](https://clerk.com/contact/support?utm_source=github&utm_medium=clerk_agent_toolkit)
+
+
+
+> ℹ️ Developer Preview
+>
+> Agent behavior is typically non-deterministic. Ensure you thoroughly test your integration and evaluate your application's performance. Additionally, consider scoping this toolkit's tools to specific users to limit resource access.
+>
+> If your app's code path is predetermined, it's always preferable to call APIs directly instead of using agents and tool calling.
+>
+> This SDK is recommended for testing purposes only unless you are confident in the agent's behavior and have implemented necessary security measures such as guardrails and best practices.
+
+## Table of Contents
+1. [Getting Started](#getting-started)
+2. [Public APIs](#public-apis)
+3. [Use with Vercel's AI SDK](#use-with-vercels-ai-sdk)
+4. [Use with Langchain](#use-with-langchain)
+5. [Advanced Usage](#advanced-usage)
+6. [Support](#support)
+
+## Getting Started
+
+Use this SDK to integrate [Clerk](https://clerk.com/?utm_source=github&utm_medium=clerk_agent_toolkit) into your agentic workflows. The Clerk Agent Toolkit enables popular agent frameworks, including Vercel's AI SDK and LangChain, to integrate with Clerk using tools (also known as function calling).
+
+This package exposes a subset of Clerk's functionality to agent frameworks, allowing you to build powerful agentic systems capable of managing users, user data, organizations, and more.
+
+## Public APIs
+
+The Clerk Agent Toolkit package provides two main import paths:
+
+- `@clerk/agent-toolkit/ai-sdk`: Helpers for integrating with Vercel's AI SDK.
+- `@clerk/agent-toolkit/langchain`: Helpers for integrating with Langchain.
+
+The toolkit offers the same tools and core APIs across frameworks, but their public interfaces may vary slightly to align with each framework's design:
+
+- `createClerkToolkit(options)`: Instantiates a new Clerk toolkit.
+- `toolkit.injectSessionClaims(systemPrompt)`: Injects session claims (userId, sessionId, orgId, etc.) into the system prompt, making them accessible to the AI model.
+- `toolkit.users()`: Provides tools for managing users.
+- `toolkit.organizations()`: Provides tools for managing organizations.
+- `toolkit.allTools()`: Returns all available tools.
+- `toolkit.toolMap()`: **(Langchain only)** Returns an object mapping available tools, useful for calling tools by name.
+
+For more details on each tool, refer to the framework-specific directories or the [Clerk BAPI documentation](https://clerk.com/docs/reference/backend-api).
+
+### Prerequisites
+- `ai-sdk`: `"^3.4.7 || ^4.0.0"`, or `langchain`: `"^0.3.6"`
+- A Clerk application
+- An API key for an AI model compatible with Langchain
+
+### Example Repository
+- [Clerk AI SDK Example](https://github.com/clerk/agent-toolkit-example)
+
+## Use with Vercel's AI SDK
+
+1. Install the Clerk Agent Toolkit package:
+
+ ```shell
+ npm install @clerk/agent-toolkit
+ ```
+
+2. Set the Clerk secret key as an environment variable in your project. Ensure you also configure any required LLM model keys.
+
+ ```
+ CLERK_SECRET_KEY=sk_
+ ```
+
+3. Import the helper from the `/ai-sdk` path, instantiate a new Clerk `toolkit`, and use it in your agent function:
+
+```typescript
+// Import the helper from the ai-sdk path
+import { createClerkToolkit } from "@clerk/agent-toolkit/ai-sdk";
+import { openai } from "@ai-sdk/openai";
+import { streamText } from "ai";
+import { auth } from "@clerk/nextjs/server";
+import { systemPrompt } from "@/lib/ai/prompts";
+
+export const maxDuration = 30;
+
+export async function POST(req: Request) {
+ const { messages } = await req.json();
+ // Optional - get the userId from the request
+ const { userId } = await auth.protect();
+
+ // Instantiate a new Clerk toolkit
+ // Optional - scope the toolkit to a specific user
+ const toolkit = await createClerkToolkit({ context: { userId } });
+
+ const result = streamText({
+ model: openai("gpt-4o"),
+ messages,
+ // Optional - inject session claims into the system prompt
+ system: toolkit.injectSessionClaims(systemPrompt),
+ tools: {
+ // Provide the tools you want to use
+ ...toolkit.users(),
+ ...toolkit.organizations(),
+ },
+ });
+
+ return result.toDataStreamResponse();
+}
+```
+
+## Use with Langchain
+
+
+
+1. Install the Clerk Agent Toolkit package:
+
+ ```shell
+ npm install @clerk/agent-toolkit
+ ```
+
+2. Set the Clerk secret key as an environment variable:
+
+ ```shell
+ CLERK_SECRET_KEY=sk_
+ ```
+
+3. Import the helper from the `/langchain` path, instantiate a new Clerk `toolkit`, and use it in your agent function:
+
+```typescript
+// Import the helper from the langchain path
+import { createClerkToolkit } from "@clerk/agent-toolkit/langchain";
+import { ChatOpenAI } from "@langchain/openai";
+import { auth } from "@clerk/nextjs/server";
+import { HumanMessage, SystemMessage } from "@langchain/core/messages";
+import { LangChainAdapter } from "ai";
+import { systemPrompt } from "@/lib/ai/prompts";
+
+export const maxDuration = 30;
+
+export async function POST(req: Request) {
+ const { prompt } = await req.json();
+ const { userId } = await auth.protect();
+
+ // Instantiate a new Clerk toolkit
+ // Optional - scope the toolkit to a specific user
+ const toolkit = await createClerkToolkit({ context: { userId } });
+
+ const model = new ChatOpenAI({ model: "gpt-4o", temperature: 0 });
+
+ // Bind the tools you want to use to the model
+ const modelWithTools = model.bindTools(toolkit.users());
+
+ const messages = [new SystemMessage(toolkit.injectSessionClaims(systemPrompt)), new HumanMessage(prompt)];
+ const aiMessage = await modelWithTools.invoke(messages);
+ messages.push(aiMessage);
+
+ for (const toolCall of aiMessage.tool_calls || []) {
+ // Call the selected tool
+ const selectedTool = toolkit.toolMap()[toolCall.name];
+ const toolMessage = await selectedTool.invoke(toolCall);
+ messages.push(toolMessage);
+ }
+
+ // To simplify the setup, this example uses the ai-sdk langchain adapter
+ // to stream the results back to the /langchain page.
+ // For more details, see: https://sdk.vercel.ai/providers/adapters/langchain
+ const stream = await modelWithTools.stream(messages);
+ return LangChainAdapter.toDataStreamResponse(stream);
+}
+
+````
+
+## Advanced Usage
+
+### Using a Custom `clerkClient`
+
+If you need to set the Clerk secret key dynamically or use different Clerk instances, pass a custom `clerkClient`:
+
+```typescript
+import { createClerkToolkit } from "@clerk/agent-toolkit/ai-sdk";
+import { createClerkClient } from "@clerk/backend";
+
+export async function POST(req: Request) {
+ // Create a new Clerk client
+ const clerkClient = createClerkClient({ secretKey: "sk_" });
+
+ // Instantiate a new Clerk toolkit with the custom client
+ const toolkit = await createClerkToolkit({ clerkClient });
+
+ // Use the toolkit as usual
+ const result = streamText({
+ model: openai("gpt-4o"),
+ messages,
+ tools: toolkit.users()
+ });
+}
+```
+
+## Support
+
+You can get in touch with us in any of the following ways:
+
+- Join our official community [Discord server](https://clerk.com/discord)
+- On [our support page](https://clerk.com/contact/support?utm_source=github&utm_medium=clerk_agent_toolkit)
+
+## Contributing
+
+We're open to all community contributions! If you'd like to contribute in any way, please read [our contribution guidelines](https://github.com/clerk/javascript/blob/main/docs/CONTRIBUTING.md) and [code of conduct](https://github.com/clerk/javascript/blob/main/docs/CODE_OF_CONDUCT.md).
+
+## License
+
+This project is licensed under the **MIT license**.
+
+See [LICENSE](https://github.com/clerk/javascript/blob/main/packages/agent-toolkit/LICENSE) for more information.
diff --git a/packages/agent-toolkit/package.json b/packages/agent-toolkit/package.json
new file mode 100644
index 00000000000..d8a88a0be86
--- /dev/null
+++ b/packages/agent-toolkit/package.json
@@ -0,0 +1,66 @@
+{
+ "name": "@clerk/agent-toolkit",
+ "version": "0.0.1",
+ "description": "Clerk Toolkit for AI Agents",
+ "homepage": "https://clerk.com/",
+ "bugs": {
+ "url": "https://github.com/clerk/javascript/issues"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/clerk/javascript.git",
+ "directory": "packages/agent-toolkit"
+ },
+ "license": "MIT",
+ "author": "Clerk",
+ "sideEffects": false,
+ "files": [
+ "dist"
+ ],
+ "exports": {
+ "./langchain": {
+ "types": "./dist/langchain/index.d.ts",
+ "require": "./dist/langchain/index.js",
+ "import": "./dist/langchain/index.mjs"
+ },
+ "./ai-sdk": {
+ "types": "./dist/ai-sdk/index.d.ts",
+ "require": "./dist/ai-sdk/index.js",
+ "import": "./dist/ai-sdk/index.mjs"
+ }
+ },
+ "scripts": {
+ "build": "tsup --env.NODE_ENV production",
+ "clean": "rimraf ./dist",
+ "dev": "tsup --watch",
+ "lint": "eslint src",
+ "lint:attw": "attw --pack .",
+ "lint:publint": "publint",
+ "test": "jest",
+ "test:cache:clear": "jest --clearCache --useStderr"
+ },
+ "dependencies": {
+ "@clerk/backend": "workspace:^",
+ "@clerk/shared": "workspace:^",
+ "@clerk/types": "workspace:^",
+ "zod": "^3.24.1"
+ },
+ "peerDependencies": {
+ "@langchain/core": "^0.3.6",
+ "ai": "^3.4.7 || ^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@langchain/core": {
+ "optional": true
+ },
+ "ai": {
+ "optional": true
+ }
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/packages/agent-toolkit/src/ai-sdk/adapter.ts b/packages/agent-toolkit/src/ai-sdk/adapter.ts
new file mode 100644
index 00000000000..b9ae77033f7
--- /dev/null
+++ b/packages/agent-toolkit/src/ai-sdk/adapter.ts
@@ -0,0 +1,12 @@
+import type { Tool } from 'ai';
+import { tool } from 'ai';
+
+import type { SdkAdapter } from '../lib/types';
+
+export const adapter: SdkAdapter = (clerkClient, context, clerkTool) => {
+ return tool({
+ description: clerkTool.description,
+ parameters: clerkTool.parameters,
+ execute: clerkTool.bindRunnable(clerkClient, context),
+ });
+};
diff --git a/packages/agent-toolkit/src/ai-sdk/index.ts b/packages/agent-toolkit/src/ai-sdk/index.ts
new file mode 100644
index 00000000000..7ad9a86bf1c
--- /dev/null
+++ b/packages/agent-toolkit/src/ai-sdk/index.ts
@@ -0,0 +1,43 @@
+import { clerkClient as _clerkClient } from '../lib/clerk-client';
+import { defaultToolkitContext } from '../lib/constants';
+import { injectSessionClaims } from '../lib/inject-session-claims';
+import { flatTools, tools } from '../lib/tools';
+import type { ClerkToolkitBase, CreateClerkToolkitParams } from '../lib/types';
+import { shallowTransform } from '../lib/utils';
+import { adapter } from './adapter';
+
+export type ClerkToolkit = ClerkToolkitBase & {
+ /**
+ * Returns an object with all the tools from all categories in the Clerk toolkit.
+ *
+ * Most LLM providers recommend that for each LLM call, the number of available tools should be kept to a minimum,
+ * usually around 10-20 tools. This increases the LLM's accuracy when picking the right tool.
+ *
+ * As a result, we also recommend to use the fine-grained tool categories, for example, `toolkit.users` instead.
+ */
+ allTools: () => { [key in keyof typeof flatTools]: ReturnType };
+} & {
+ [key in keyof typeof tools]: () => { [tool in keyof (typeof tools)[key]]: ReturnType };
+};
+
+export const createClerkToolkit = async (params: CreateClerkToolkitParams = {}): Promise => {
+ const clerkClient = params.clerkClient || _clerkClient;
+ const context = params.context || defaultToolkitContext;
+
+ const adaptedTools = shallowTransform(tools, toolSection => {
+ return () =>
+ shallowTransform(toolSection, t => {
+ return adapter(clerkClient, context, t);
+ });
+ });
+
+ const allTools = () => {
+ return shallowTransform(flatTools, t => adapter(clerkClient, context, t));
+ };
+
+ return {
+ ...adaptedTools,
+ allTools,
+ injectSessionClaims: injectSessionClaims(context),
+ };
+};
diff --git a/packages/agent-toolkit/src/global.d.ts b/packages/agent-toolkit/src/global.d.ts
new file mode 100644
index 00000000000..1ae75219e34
--- /dev/null
+++ b/packages/agent-toolkit/src/global.d.ts
@@ -0,0 +1,6 @@
+declare global {
+ const PACKAGE_NAME: string;
+ const PACKAGE_VERSION: string;
+}
+
+export {};
diff --git a/packages/agent-toolkit/src/langchain/adapter.ts b/packages/agent-toolkit/src/langchain/adapter.ts
new file mode 100644
index 00000000000..85bce7461eb
--- /dev/null
+++ b/packages/agent-toolkit/src/langchain/adapter.ts
@@ -0,0 +1,13 @@
+import type { StructuredTool } from '@langchain/core/tools';
+import { tool } from '@langchain/core/tools';
+
+import type { SdkAdapter } from '../lib/types';
+
+// https://js.langchain.com/docs/how_to/custom_tools
+export const adapter: SdkAdapter = (clerkClient, context, clerkTool) => {
+ return tool(clerkTool.bindRunnable(clerkClient, context), {
+ name: clerkTool.name,
+ description: clerkTool.description,
+ schema: clerkTool.parameters,
+ });
+};
diff --git a/packages/agent-toolkit/src/langchain/index.ts b/packages/agent-toolkit/src/langchain/index.ts
new file mode 100644
index 00000000000..f2c6e0099e1
--- /dev/null
+++ b/packages/agent-toolkit/src/langchain/index.ts
@@ -0,0 +1,48 @@
+import { clerkClient as _clerkClient } from '../lib/clerk-client';
+import { defaultToolkitContext } from '../lib/constants';
+import { injectSessionClaims } from '../lib/inject-session-claims';
+import { flatTools, tools } from '../lib/tools';
+import type { ClerkToolkitBase, CreateClerkToolkitParams } from '../lib/types';
+import { shallowTransform } from '../lib/utils';
+import { adapter } from './adapter';
+
+export type ClerkToolkit = ClerkToolkitBase & {
+ /**
+ * Returns an array containing all tools from all categories in the Clerk toolkit.
+ *
+ * Most LLM providers recommend that for each LLM call, the number of available tools should be kept to a minimum,
+ * usually around 10-20 tools. This increases the LLM's accuracy when picking the right tool.
+ *
+ * As a result, we also recommend to use the fine-grained tool categories, for example, `toolkit.users` instead.
+ */
+ allTools: () => Array>;
+ /**
+ * Returns an object with all the tools from all categories in the Clerk toolkit.
+ * Useful when using tool calling with Langchain messages (e.g. `tool_calls`).
+ */
+ toolMap: () => { [key in keyof typeof flatTools]: ReturnType };
+} & {
+ [key in keyof typeof tools]: () => Array>;
+};
+
+export const createClerkToolkit = async (params: CreateClerkToolkitParams = {}): Promise => {
+ const clerkClient = params.clerkClient || _clerkClient;
+ const context = params.context || defaultToolkitContext;
+
+ const adaptedTools = shallowTransform(tools, toolSection => {
+ return () => Object.values(toolSection).map(t => adapter(clerkClient, context, t));
+ });
+
+ const allTools = () => {
+ return Object.values(flatTools).map(t => adapter(clerkClient, context, t));
+ };
+
+ const toolMap = shallowTransform(flatTools, t => adapter(clerkClient, context, t));
+
+ return {
+ ...adaptedTools,
+ allTools,
+ toolMap: () => toolMap,
+ injectSessionClaims: injectSessionClaims(context),
+ };
+};
diff --git a/packages/agent-toolkit/src/lib/clerk-client.ts b/packages/agent-toolkit/src/lib/clerk-client.ts
new file mode 100644
index 00000000000..5b709e713ad
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/clerk-client.ts
@@ -0,0 +1,22 @@
+import { createClerkClient } from '@clerk/backend';
+import { apiUrlFromPublishableKey } from '@clerk/shared/apiUrlFromPublishableKey';
+
+const API_VERSION = process.env.CLERK_API_VERSION || 'v1';
+const SECRET_KEY = process.env.CLERK_SECRET_KEY || '';
+const PUBLISHABLE_KEY = process.env.CLERK_PUBLISHABLE_KEY || '';
+const API_URL = process.env.CLERK_API_URL || apiUrlFromPublishableKey(PUBLISHABLE_KEY);
+const JWT_KEY = process.env.CLERK_JWT_KEY || '';
+const SDK_METADATA = {
+ name: PACKAGE_NAME,
+ version: PACKAGE_VERSION,
+ environment: process.env.NODE_ENV,
+};
+
+export const clerkClient = createClerkClient({
+ secretKey: SECRET_KEY,
+ apiUrl: API_URL,
+ apiVersion: API_VERSION,
+ jwtKey: JWT_KEY,
+ userAgent: `${PACKAGE_NAME}@${PACKAGE_VERSION}`,
+ sdkMetadata: SDK_METADATA,
+});
diff --git a/packages/agent-toolkit/src/lib/clerk-tool.ts b/packages/agent-toolkit/src/lib/clerk-tool.ts
new file mode 100644
index 00000000000..8c82b5c6d82
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/clerk-tool.ts
@@ -0,0 +1,55 @@
+import type { ClerkClient } from '@clerk/backend';
+import type { ZodObject } from 'zod';
+
+import type { ToolkitContext } from './types';
+
+export interface ClerkTool {
+ /**
+ * The name of the tool. This can be used to reference the tool in the code.
+ * A descriptive LLM-readable string.
+ */
+ name: string;
+ /**
+ * A descriptive prompt explaining the tool's purpose, usage and input parameters.
+ * Ths is intended to be used by the underlying LLM.
+ * To avoid duplication, the description can reference the parameters by using the `$parameters` prefix.
+ */
+ description: string;
+ /**
+ * The Zod schema for the input parameters of the tool
+ */
+ parameters: ZodObject;
+ /**
+ * The actual implementation of the tool.
+ */
+ bindRunnable: (clerkClient: ClerkClient, context: ToolkitContext) => (input: any) => Promise;
+}
+
+const trimLines = (text: string) =>
+ text
+ .split('\n')
+ .map(l => l.trim())
+ .filter(Boolean)
+ .join('\n');
+
+export const ClerkTool = (params: ClerkTool): ClerkTool => {
+ const schemaEntries = Object.entries(params.parameters.shape);
+ const args =
+ schemaEntries.length === 0
+ ? 'Takes no arguments'
+ : Object.entries(params.parameters.shape)
+ .map(([key, value]) => {
+ return `- ${key}: ${(value as any).description || ''}`;
+ })
+ .join('\n');
+
+ const description = trimLines(`
+ Tool name:
+ ${params.name}
+ Description:
+ ${params.description}.
+ Arguments:
+ ${args}
+ `);
+ return { ...params, description };
+};
diff --git a/packages/agent-toolkit/src/lib/constants.ts b/packages/agent-toolkit/src/lib/constants.ts
new file mode 100644
index 00000000000..7f23a9bdebe
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/constants.ts
@@ -0,0 +1,5 @@
+import type {ToolkitContext} from "./types";
+
+export const defaultToolkitContext: ToolkitContext = {
+ allowPrivateMetadata: false,
+};
diff --git a/packages/agent-toolkit/src/lib/inject-session-claims.ts b/packages/agent-toolkit/src/lib/inject-session-claims.ts
new file mode 100644
index 00000000000..db31cf5892e
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/inject-session-claims.ts
@@ -0,0 +1,18 @@
+import type { ToolkitContext } from './types';
+
+export const injectSessionClaims = (context: ToolkitContext) => (prompt: string) => {
+ if (!context.sessionClaims && !context.userId) {
+ return prompt;
+ }
+
+ const lines = [];
+ lines.push(`# Signed-in user info:`);
+ lines.push(
+ context.sessionClaims?.sub || context.userId
+ ? `Your userId is ${context.sessionClaims?.sub || context.userId}`
+ : '',
+ );
+ lines.push(context.sessionClaims?.sid ? `Your sessionId is ${context.sessionClaims?.sid}` : '');
+ lines.push(prompt);
+ return lines.filter(Boolean).join('\n');
+};
diff --git a/packages/agent-toolkit/src/lib/tools/index.ts b/packages/agent-toolkit/src/lib/tools/index.ts
new file mode 100644
index 00000000000..a7714fe5291
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/tools/index.ts
@@ -0,0 +1,15 @@
+import { users } from './user-tools';
+
+export const tools = {
+ /**
+ * Tools for interacting with users.
+ * This is a wrapper around the `clerkClient.users` API.
+ * For more information, see the [Clerk API documentation](https://clerk.com/docs/reference/backend-api/tag/Users).
+ */
+ users,
+} as const;
+
+// Just to help with types later on
+export const flatTools = {
+ ...users,
+};
diff --git a/packages/agent-toolkit/src/lib/tools/user-tools.ts b/packages/agent-toolkit/src/lib/tools/user-tools.ts
new file mode 100644
index 00000000000..76676aba762
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/tools/user-tools.ts
@@ -0,0 +1,52 @@
+import { z } from 'zod';
+
+import { ClerkTool } from '../clerk-tool';
+import { prunePrivateData } from '../utils';
+
+const getUserId = ClerkTool({
+ name: 'getUserId',
+ description: `
+ Get the userId of the current user if signed in, otherwise return null.
+ `,
+ parameters: z.object({}),
+ bindRunnable: (clerkClient, context) => () => {
+ return Promise.resolve(context.userId || null);
+ },
+});
+
+const getUser = ClerkTool({
+ name: 'getUser',
+ description: `
+ Retrieves information about a single User by their userId, if the userId is valid.
+ `,
+ parameters: z.object({
+ userId: z.string().describe('(string): The userId of the User to retrieve'),
+ }),
+ bindRunnable: (clerkClient, context) => async params => {
+ const res = await clerkClient.users.getUser(context.userId || params.userId);
+ return prunePrivateData(context, res.raw);
+ },
+});
+
+const updateUserPublicMetadata = ClerkTool({
+ name: 'updateUserPublicMetadata',
+ description: `
+ Updates the public metadata associated with the specified user by merging existing values with the provided parameters.
+ A "deep" merge will be performed - "deep" means that any nested JSON objects will be merged as well. You can remove metadata keys at any level by setting their value to null.
+ `,
+ parameters: z.object({
+ userId: z.string().describe('(string): The userId of the User to update'),
+ metadata: z.record(z.string(), z.any()).describe('(Record): The new public metadata to set'),
+ }),
+ bindRunnable: (clerkClient, context) => async params => {
+ const { userId, metadata } = params;
+ const res = await clerkClient.users.updateUserMetadata(context.userId || userId, { publicMetadata: metadata });
+ return prunePrivateData(context, res.raw);
+ },
+});
+
+export const users = {
+ getUserId,
+ getUser,
+ updateUserPublicMetadata,
+} as const;
diff --git a/packages/agent-toolkit/src/lib/types.ts b/packages/agent-toolkit/src/lib/types.ts
new file mode 100644
index 00000000000..1c458013db4
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/types.ts
@@ -0,0 +1,26 @@
+import type { ClerkClient } from '@clerk/backend';
+import type { SignedInAuthObject } from '@clerk/backend/internal';
+
+import type { ClerkTool } from './clerk-tool';
+
+export type SdkAdapter = (clerkClient: ClerkClient, context: ToolkitContext, clerkTool: ClerkTool) => T;
+
+export type ToolkitContext = {
+ userId?: string;
+ sessionClaims?: SignedInAuthObject['sessionClaims'];
+ allowPrivateMetadata?: boolean;
+};
+
+export type CreateClerkToolkitParams = {
+ clerkClient?: ClerkClient;
+ context?: ToolkitContext;
+};
+
+export type ClerkToolkitBase = {
+ /**
+ * Augment the system prompt with data about the current session.
+ * This usually contains the userId, the sessionId, the organizationId, etc.
+ * This property uses the data passed to `createClerkToolkit`.
+ */
+ injectSessionClaims: (prompt: string) => string;
+};
diff --git a/packages/agent-toolkit/src/lib/utils.ts b/packages/agent-toolkit/src/lib/utils.ts
new file mode 100644
index 00000000000..2400130332f
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/utils.ts
@@ -0,0 +1,66 @@
+import type { ToolkitContext } from './types';
+
+// A helper type that maps T to a new type with every leaf replaced by R.
+type DeepTransform =
+ T extends Array ? DeepTransform[] : T extends object ? { [K in keyof T]: DeepTransform } : R;
+
+/**
+ * Recursively transforms every value in an object (or array) by applying a function.
+ *
+ * The result has the same structure as the input object,
+ but each leaf value is replaced with the return type R of the transform function.
+ */
+export function deepTransform(input: T, transformFn: (value: any) => R): DeepTransform {
+ if (Array.isArray(input)) {
+ // Recursively transform each element of the array.
+ return input.map(item => deepTransform(item, transformFn)) as DeepTransform;
+ } else if (input !== null && typeof input === 'object') {
+ // Recursively transform each property of the object.
+ const result: any = {};
+ for (const key in input) {
+ if (Object.prototype.hasOwnProperty.call(input, key)) {
+ result[key] = deepTransform((input as any)[key], transformFn);
+ }
+ }
+ return result as DeepTransform;
+ } else {
+ // For non-objects, apply the transform function.
+ return transformFn(input) as DeepTransform;
+ }
+}
+
+/**
+ * A mapped type that replaces every property in T with type R.
+ */
+type ShallowTransform = {
+ [K in keyof T]: R;
+};
+
+/**
+ * Transforms the top-level values of an object using a transformation function.
+ *
+ */
+export function shallowTransform(
+ input: T,
+ transformFn: (value: T[keyof T]) => R,
+): ShallowTransform {
+ const result = {} as ShallowTransform;
+ for (const key in input) {
+ if (Object.prototype.hasOwnProperty.call(input, key)) {
+ const typedKey = key as keyof T;
+ result[typedKey] = transformFn(input[typedKey]);
+ }
+ }
+ return result;
+}
+
+export const prunePrivateData = (context: ToolkitContext, o?: Record | null) => {
+ if (context.allowPrivateMetadata) {
+ return o;
+ }
+
+ if (o && o.private_metadata) {
+ delete o.private_metadata;
+ }
+ return o;
+};
diff --git a/packages/agent-toolkit/tsconfig.json b/packages/agent-toolkit/tsconfig.json
new file mode 100644
index 00000000000..57b39d50251
--- /dev/null
+++ b/packages/agent-toolkit/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "moduleResolution": "NodeNext",
+ "module": "NodeNext",
+ "sourceMap": false,
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "allowJs": true,
+ "target": "ES2020",
+ "emitDeclarationOnly": true,
+ "declaration": true,
+ "declarationMap": true,
+ "outDir": "dist",
+ "resolveJsonModule": true,
+ "declarationDir": "dist/types"
+ },
+ "include": ["src"]
+}
diff --git a/packages/agent-toolkit/tsconfig.test.json b/packages/agent-toolkit/tsconfig.test.json
new file mode 100644
index 00000000000..5635d6cd1b7
--- /dev/null
+++ b/packages/agent-toolkit/tsconfig.test.json
@@ -0,0 +1,6 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "sourceMap": true
+ }
+}
diff --git a/packages/agent-toolkit/tsup.config.ts b/packages/agent-toolkit/tsup.config.ts
new file mode 100644
index 00000000000..7eb4dadc8e0
--- /dev/null
+++ b/packages/agent-toolkit/tsup.config.ts
@@ -0,0 +1,23 @@
+import { defineConfig } from 'tsup';
+
+import { name, version } from './package.json';
+
+export default defineConfig(overrideOptions => {
+ const isProd = overrideOptions.env?.NODE_ENV === 'production';
+
+ return {
+ entry: ['src/ai-sdk/index.ts', 'src/langchain/index.ts'],
+ dts: true,
+ // onSuccess: 'tsc',
+ minify: isProd,
+ clean: true,
+ sourcemap: true,
+ format: ['cjs', 'esm'],
+ // legacyOutput: true,
+ define: {
+ PACKAGE_NAME: `"${name}"`,
+ PACKAGE_VERSION: `"${version}"`,
+ __DEV__: `${!isProd}`,
+ },
+ };
+});
diff --git a/packages/backend/src/api/resources/User.ts b/packages/backend/src/api/resources/User.ts
index f70b7da959a..5da7b6a97ef 100644
--- a/packages/backend/src/api/resources/User.ts
+++ b/packages/backend/src/api/resources/User.ts
@@ -6,6 +6,12 @@ import { SamlAccount } from './SamlAccount';
import { Web3Wallet } from './Web3Wallet';
export class User {
+ private _raw: UserJSON | null = null;
+
+ public get raw(): UserJSON | null {
+ return this._raw;
+ }
+
constructor(
readonly id: string,
readonly passwordEnabled: boolean,
@@ -42,7 +48,7 @@ export class User {
) {}
static fromJSON(data: UserJSON): User {
- return new User(
+ const res = new User(
data.id,
data.password_enabled,
data.totp_enabled,
@@ -76,6 +82,8 @@ export class User {
data.delete_self_enabled,
data.legal_accepted_at,
);
+ res._raw = data;
+ return res;
}
get primaryEmailAddress() {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6f58ebff3d5..f109f9a60cb 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -302,6 +302,27 @@ importers:
specifier: catalog:repo
version: 8.3.0
+ packages/agent-toolkit:
+ dependencies:
+ '@clerk/backend':
+ specifier: workspace:^
+ version: link:../backend
+ '@clerk/shared':
+ specifier: workspace:^
+ version: link:../shared
+ '@clerk/types':
+ specifier: workspace:^
+ version: link:../types
+ '@langchain/core':
+ specifier: ^0.3.6
+ version: 0.3.39
+ ai:
+ specifier: ^3.4.7 || ^4.0.0
+ version: 4.1.34(react@18.3.1)(zod@3.24.1)
+ zod:
+ specifier: ^3.24.1
+ version: 3.24.1
+
packages/astro:
dependencies:
'@clerk/backend':
@@ -541,7 +562,7 @@ importers:
version: 8.2.2
next:
specifier: ^14.2.23
- version: 14.2.23(@babel/core@7.26.7)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 14.2.23(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
type-fest:
specifier: ^4.33.0
version: 4.33.0
@@ -710,7 +731,7 @@ importers:
version: 4.2.2
next:
specifier: ^14.2.23
- version: 14.2.23(@babel/core@7.26.7)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 14.2.23(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
packages/nuxt:
dependencies:
@@ -1150,6 +1171,40 @@ packages:
'@adobe/css-tools@4.4.0':
resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==}
+ '@ai-sdk/provider-utils@2.1.6':
+ resolution: {integrity: sha512-Pfyaj0QZS22qyVn5Iz7IXcJ8nKIKlu2MeSAdKJzTwkAks7zdLaKVB+396Rqcp1bfQnxl7vaduQVMQiXUrgK8Gw==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ zod: ^3.0.0
+ peerDependenciesMeta:
+ zod:
+ optional: true
+
+ '@ai-sdk/provider@1.0.7':
+ resolution: {integrity: sha512-q1PJEZ0qD9rVR+8JFEd01/QM++csMT5UVwYXSN2u54BrVw/D8TZLTeg2FEfKK00DgAx0UtWd8XOhhwITP9BT5g==}
+ engines: {node: '>=18'}
+
+ '@ai-sdk/react@1.1.11':
+ resolution: {integrity: sha512-vfjZ7w2M+Me83HTMMrnnrmXotz39UDCMd27YQSrvt2f1YCLPloVpLhP+Y9TLZeFE/QiiRCrPYLDQm6aQJYJ9PQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ react: ^18 || ^19 || ^19.0.0-rc
+ zod: ^3.0.0
+ peerDependenciesMeta:
+ react:
+ optional: true
+ zod:
+ optional: true
+
+ '@ai-sdk/ui-utils@1.1.11':
+ resolution: {integrity: sha512-1SC9W4VZLcJtxHRv4Y0aX20EFeaEP6gUvVqoKLBBtMLOgtcZrv/F/HQRjGavGugiwlS3dsVza4X+E78fiwtlTA==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ zod: ^3.0.0
+ peerDependenciesMeta:
+ zod:
+ optional: true
+
'@alcalzone/ansi-tokenize@0.1.3':
resolution: {integrity: sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw==}
engines: {node: '>=14.13.1'}
@@ -1976,6 +2031,9 @@ packages:
'@bundled-es-modules/tough-cookie@0.1.6':
resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==}
+ '@cfworker/json-schema@4.1.1':
+ resolution: {integrity: sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==}
+
'@changesets/apply-release-plan@7.0.5':
resolution: {integrity: sha512-1cWCk+ZshEkSVEZrm2fSj1Gz8sYvxgUL4Q78+1ZZqeqfuevPTPk033/yUZ3df8BKMohkqqHfzj0HOOrG0KtXTw==}
@@ -3289,6 +3347,10 @@ packages:
'@kwsites/promise-deferred@1.1.1':
resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==}
+ '@langchain/core@0.3.39':
+ resolution: {integrity: sha512-muXs4asy1A7qDtcdznxqyBfxf4N6qxofY/S0c95vbsWa0r9YAE2PttHIjcuxSy1q2jUiTkpCcgFEjNJRQRVhEw==}
+ engines: {node: '>=18'}
+
'@leichtgewicht/ip-codec@2.0.4':
resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==}
@@ -3582,6 +3644,10 @@ packages:
'@open-draft/until@2.1.0':
resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
+ '@opentelemetry/api@1.9.0':
+ resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
+ engines: {node: '>=8.0.0'}
+
'@oslojs/encoding@1.1.0':
resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
@@ -5385,6 +5451,9 @@ packages:
'@types/debug@4.1.12':
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
+ '@types/diff-match-patch@1.0.36':
+ resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==}
+
'@types/diff@6.0.0':
resolution: {integrity: sha512-dhVCYGv3ZSbzmQaBSagrv1WJ6rXCdkyTcDyoNu1MD8JohI7pR7k8wdZEm+mvdxRKXyHVwckFzWU1vJc+Z29MlA==}
@@ -5574,6 +5643,9 @@ packages:
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
+ '@types/uuid@10.0.0':
+ resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==}
+
'@types/webextension-polyfill@0.10.7':
resolution: {integrity: sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==}
@@ -6090,6 +6162,18 @@ packages:
resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==}
engines: {node: '>=12'}
+ ai@4.1.34:
+ resolution: {integrity: sha512-9IB5duz6VbXvjibqNrvKz6++PwE8Ui5UfbOC9/CtcQN5Z9sudUQErss+maj7ptoPysD2NPjj99e0Hp183Cz5LQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ react: ^18 || ^19 || ^19.0.0-rc
+ zod: ^3.0.0
+ peerDependenciesMeta:
+ react:
+ optional: true
+ zod:
+ optional: true
+
ajv-formats@2.1.1:
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
@@ -7128,6 +7212,9 @@ packages:
resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==}
engines: {node: ^14.18.0 || >=16.10.0}
+ console-table-printer@2.12.1:
+ resolution: {integrity: sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==}
+
content-disposition@0.5.4:
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
engines: {node: '>= 0.6'}
@@ -7723,6 +7810,9 @@ packages:
didyoumean@1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
+ diff-match-patch@1.0.5:
+ resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==}
+
diff-sequences@29.6.3:
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -8253,6 +8343,10 @@ packages:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
+ eventsource-parser@3.0.0:
+ resolution: {integrity: sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==}
+ engines: {node: '>=18.0.0'}
+
exec-async@2.2.0:
resolution: {integrity: sha512-87OpwcEiMia/DeiKFzaQNBNFeN3XkkpYIh9FyOqq5mS2oKv3CBE67PXoEKcr6nodWdXNogTiQ0jE2NGuoffXPw==}
@@ -9979,6 +10073,9 @@ packages:
resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==}
engines: {node: '>=0.10.0'}
+ js-tiktoken@1.0.18:
+ resolution: {integrity: sha512-hFYx4xYf6URgcttcGvGuOBJhTxPYZ2R5eIesqCaNRJmYH8sNmsfTeWg4yu//7u1VD/qIUkgKJTpGom9oHXmB4g==}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -10107,6 +10204,11 @@ packages:
engines: {node: '>=6'}
hasBin: true
+ jsondiffpatch@0.6.0:
+ resolution: {integrity: sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+
jsonfile@4.0.0:
resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
@@ -10172,6 +10274,14 @@ packages:
kolorist@1.8.0:
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
+ langsmith@0.3.7:
+ resolution: {integrity: sha512-wakN1hxGkm1JR2PpAV7fiT7oC99LKcgxiuUrYGZWPbuj7Y8EPF19F7VNr4B+hA219bfaeWTa4Lxy2YrtPSKnQA==}
+ peerDependencies:
+ openai: '*'
+ peerDependenciesMeta:
+ openai:
+ optional: true
+
language-subtag-registry@0.3.23:
resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==}
@@ -10987,6 +11097,10 @@ packages:
resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==}
hasBin: true
+ mustache@4.2.0:
+ resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
+ hasBin: true
+
mute-stream@2.0.0:
resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==}
engines: {node: ^18.17.0 || >=20.5.0}
@@ -11489,6 +11603,10 @@ packages:
resolution: {integrity: sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==}
engines: {node: '>=16'}
+ p-queue@6.6.2:
+ resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==}
+ engines: {node: '>=8'}
+
p-queue@8.0.1:
resolution: {integrity: sha512-NXzu9aQJTAzbBqOt2hwsR63ea7yvxJc0PwN/zobNAudYfb1B7R08SzB4TsLeSbUCuG467NhnoT0oO6w1qRO+BA==}
engines: {node: '>=18'}
@@ -11501,6 +11619,10 @@ packages:
resolution: {integrity: sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==}
engines: {node: '>=16.17'}
+ p-timeout@3.2.0:
+ resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==}
+ engines: {node: '>=8'}
+
p-timeout@5.1.0:
resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==}
engines: {node: '>=12'}
@@ -12978,6 +13100,9 @@ packages:
simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+ simple-wcswidth@1.0.1:
+ resolution: {integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==}
+
sirv@1.0.19:
resolution: {integrity: sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==}
engines: {node: '>= 10'}
@@ -13597,6 +13722,10 @@ packages:
throttleit@1.0.1:
resolution: {integrity: sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==}
+ throttleit@2.1.0:
+ resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==}
+ engines: {node: '>=18'}
+
through2@2.0.5:
resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==}
@@ -14300,6 +14429,10 @@ packages:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'}
+ uuid@10.0.0:
+ resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
+ hasBin: true
+
uuid@7.0.3:
resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==}
hasBin: true
@@ -15057,10 +15190,10 @@ packages:
resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==}
engines: {node: '>= 14'}
- zod-to-json-schema@3.23.3:
- resolution: {integrity: sha512-TYWChTxKQbRJp5ST22o/Irt9KC5nj7CdBKYB/AosCRdj/wxEMvv4NNaj9XVUHDOIp53ZxArGhnw5HMZziPFjog==}
+ zod-to-json-schema@3.24.1:
+ resolution: {integrity: sha512-3h08nf3Vw3Wl3PK+q3ow/lIil81IT2Oa7YpQyUUDsEWbXveMesdfK1xBd2RhCkynwZndAxixji/7SYJJowr62w==}
peerDependencies:
- zod: ^3.23.3
+ zod: ^3.24.1
zod-to-ts@1.2.0:
resolution: {integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==}
@@ -15099,6 +15232,37 @@ snapshots:
'@adobe/css-tools@4.4.0': {}
+ '@ai-sdk/provider-utils@2.1.6(zod@3.24.1)':
+ dependencies:
+ '@ai-sdk/provider': 1.0.7
+ eventsource-parser: 3.0.0
+ nanoid: 3.3.8
+ secure-json-parse: 2.7.0
+ optionalDependencies:
+ zod: 3.24.1
+
+ '@ai-sdk/provider@1.0.7':
+ dependencies:
+ json-schema: 0.4.0
+
+ '@ai-sdk/react@1.1.11(react@18.3.1)(zod@3.24.1)':
+ dependencies:
+ '@ai-sdk/provider-utils': 2.1.6(zod@3.24.1)
+ '@ai-sdk/ui-utils': 1.1.11(zod@3.24.1)
+ swr: 2.2.5(react@18.3.1)
+ throttleit: 2.1.0
+ optionalDependencies:
+ react: 18.3.1
+ zod: 3.24.1
+
+ '@ai-sdk/ui-utils@1.1.11(zod@3.24.1)':
+ dependencies:
+ '@ai-sdk/provider': 1.0.7
+ '@ai-sdk/provider-utils': 2.1.6(zod@3.24.1)
+ zod-to-json-schema: 3.24.1(zod@3.24.1)
+ optionalDependencies:
+ zod: 3.24.1
+
'@alcalzone/ansi-tokenize@0.1.3':
dependencies:
ansi-styles: 6.2.1
@@ -16163,6 +16327,8 @@ snapshots:
'@types/tough-cookie': 4.0.5
tough-cookie: 4.1.4
+ '@cfworker/json-schema@4.1.1': {}
+
'@changesets/apply-release-plan@7.0.5':
dependencies:
'@changesets/config': 3.0.3
@@ -17729,6 +17895,23 @@ snapshots:
'@kwsites/promise-deferred@1.1.1': {}
+ '@langchain/core@0.3.39':
+ dependencies:
+ '@cfworker/json-schema': 4.1.1
+ ansi-styles: 5.2.0
+ camelcase: 6.3.0
+ decamelize: 1.2.0
+ js-tiktoken: 1.0.18
+ langsmith: 0.3.7
+ mustache: 4.2.0
+ p-queue: 6.6.2
+ p-retry: 4.6.2
+ uuid: 10.0.0
+ zod: 3.24.1
+ zod-to-json-schema: 3.24.1(zod@3.24.1)
+ transitivePeerDependencies:
+ - openai
+
'@leichtgewicht/ip-codec@2.0.4': {}
'@manypkg/find-root@1.1.0':
@@ -18246,6 +18429,8 @@ snapshots:
'@open-draft/until@2.1.0': {}
+ '@opentelemetry/api@1.9.0': {}
+
'@oslojs/encoding@1.1.0': {}
'@parcel/watcher-android-arm64@2.5.1':
@@ -21348,6 +21533,8 @@ snapshots:
dependencies:
'@types/ms': 0.7.34
+ '@types/diff-match-patch@1.0.36': {}
+
'@types/diff@6.0.0': {}
'@types/estree@1.0.5': {}
@@ -21553,6 +21740,8 @@ snapshots:
'@types/unist@3.0.3': {}
+ '@types/uuid@10.0.0': {}
+
'@types/webextension-polyfill@0.10.7': {}
'@types/webpack-env@1.18.8': {}
@@ -22363,6 +22552,18 @@ snapshots:
clean-stack: 4.2.0
indent-string: 5.0.0
+ ai@4.1.34(react@18.3.1)(zod@3.24.1):
+ dependencies:
+ '@ai-sdk/provider': 1.0.7
+ '@ai-sdk/provider-utils': 2.1.6(zod@3.24.1)
+ '@ai-sdk/react': 1.1.11(react@18.3.1)(zod@3.24.1)
+ '@ai-sdk/ui-utils': 1.1.11(zod@3.24.1)
+ '@opentelemetry/api': 1.9.0
+ jsondiffpatch: 0.6.0
+ optionalDependencies:
+ react: 18.3.1
+ zod: 3.24.1
+
ajv-formats@2.1.1(ajv@8.17.1):
optionalDependencies:
ajv: 8.17.1
@@ -22687,7 +22888,7 @@ snapshots:
xxhash-wasm: 1.0.2
yargs-parser: 21.1.1
zod: 3.24.1
- zod-to-json-schema: 3.23.3(zod@3.24.1)
+ zod-to-json-schema: 3.24.1(zod@3.24.1)
zod-to-ts: 1.2.0(typescript@5.6.3)(zod@3.24.1)
optionalDependencies:
sharp: 0.33.5
@@ -23590,6 +23791,10 @@ snapshots:
consola@3.4.0: {}
+ console-table-printer@2.12.1:
+ dependencies:
+ simple-wcswidth: 1.0.1
+
content-disposition@0.5.4:
dependencies:
safe-buffer: 5.2.1
@@ -24212,6 +24417,8 @@ snapshots:
didyoumean@1.2.2: {}
+ diff-match-patch@1.0.5: {}
+
diff-sequences@29.6.3: {}
diff@4.0.2:
@@ -24937,6 +25144,8 @@ snapshots:
events@3.3.0: {}
+ eventsource-parser@3.0.0: {}
+
exec-async@2.2.0: {}
execa@1.0.0:
@@ -27162,6 +27371,10 @@ snapshots:
js-levenshtein@1.1.6: {}
+ js-tiktoken@1.0.18:
+ dependencies:
+ base64-js: 1.5.1
+
js-tokens@4.0.0: {}
js-tokens@9.0.1: {}
@@ -27365,6 +27578,12 @@ snapshots:
json5@2.2.3: {}
+ jsondiffpatch@0.6.0:
+ dependencies:
+ '@types/diff-match-patch': 1.0.36
+ chalk: 5.4.1
+ diff-match-patch: 1.0.5
+
jsonfile@4.0.0:
optionalDependencies:
graceful-fs: 4.2.11
@@ -27441,6 +27660,16 @@ snapshots:
kolorist@1.8.0: {}
+ langsmith@0.3.7:
+ dependencies:
+ '@types/uuid': 10.0.0
+ chalk: 4.1.2
+ console-table-printer: 2.12.1
+ p-queue: 6.6.2
+ p-retry: 4.6.2
+ semver: 7.6.3
+ uuid: 10.0.0
+
language-subtag-registry@0.3.23: {}
language-tags@1.0.9:
@@ -28545,6 +28774,8 @@ snapshots:
dns-packet: 5.6.0
thunky: 1.1.0
+ mustache@4.2.0: {}
+
mute-stream@2.0.0: {}
mv@2.1.1:
@@ -28583,7 +28814,7 @@ snapshots:
nested-error-stacks@2.1.1: {}
- next@14.2.23(@babel/core@7.26.7)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ next@14.2.23(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@next/env': 14.2.23
'@swc/helpers': 0.5.5
@@ -28604,6 +28835,7 @@ snapshots:
'@next/swc-win32-arm64-msvc': 14.2.23
'@next/swc-win32-ia32-msvc': 14.2.23
'@next/swc-win32-x64-msvc': 14.2.23
+ '@opentelemetry/api': 1.9.0
'@playwright/test': 1.44.1
transitivePeerDependencies:
- '@babel/core'
@@ -29279,6 +29511,11 @@ snapshots:
p-map@6.0.0: {}
+ p-queue@6.6.2:
+ dependencies:
+ eventemitter3: 4.0.7
+ p-timeout: 3.2.0
+
p-queue@8.0.1:
dependencies:
eventemitter3: 5.0.1
@@ -29295,6 +29532,10 @@ snapshots:
is-network-error: 1.1.0
retry: 0.13.1
+ p-timeout@3.2.0:
+ dependencies:
+ p-finally: 1.0.0
+
p-timeout@5.1.0: {}
p-timeout@6.1.3: {}
@@ -30976,6 +31217,8 @@ snapshots:
is-arrayish: 0.3.2
optional: true
+ simple-wcswidth@1.0.1: {}
+
sirv@1.0.19:
dependencies:
'@polka/url': 1.0.0-next.28
@@ -31696,6 +31939,8 @@ snapshots:
throttleit@1.0.1: {}
+ throttleit@2.1.0: {}
+
through2@2.0.5:
dependencies:
readable-stream: 2.3.8
@@ -32373,6 +32618,8 @@ snapshots:
utils-merge@1.0.1: {}
+ uuid@10.0.0: {}
+
uuid@7.0.3: {}
uuid@8.3.2: {}
@@ -33322,7 +33569,7 @@ snapshots:
compress-commons: 6.0.2
readable-stream: 4.7.0
- zod-to-json-schema@3.23.3(zod@3.24.1):
+ zod-to-json-schema@3.24.1(zod@3.24.1):
dependencies:
zod: 3.24.1
From 592773f80c6fe710816eb088e7e7ee77ac2c788e Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 02:42:04 +0200
Subject: [PATCH 02/18] feat(agent-toolkit): Introduce @clerk/agent-toolkit
package
---
.changeset/many-pumpkins-double.md | 8 +
packages/agent-toolkit/LICENSE | 21 ++
packages/agent-toolkit/README.md | 230 +++++++++++++++
packages/agent-toolkit/package.json | 66 +++++
packages/agent-toolkit/src/ai-sdk/adapter.ts | 12 +
packages/agent-toolkit/src/ai-sdk/index.ts | 43 +++
packages/agent-toolkit/src/global.d.ts | 6 +
.../agent-toolkit/src/langchain/adapter.ts | 13 +
packages/agent-toolkit/src/langchain/index.ts | 48 ++++
.../agent-toolkit/src/lib/clerk-client.ts | 22 ++
packages/agent-toolkit/src/lib/clerk-tool.ts | 55 ++++
packages/agent-toolkit/src/lib/constants.ts | 5 +
.../src/lib/inject-session-claims.ts | 18 ++
packages/agent-toolkit/src/lib/tools/index.ts | 15 +
.../agent-toolkit/src/lib/tools/user-tools.ts | 52 ++++
packages/agent-toolkit/src/lib/types.ts | 26 ++
packages/agent-toolkit/src/lib/utils.ts | 66 +++++
packages/agent-toolkit/tsconfig.json | 19 ++
packages/agent-toolkit/tsconfig.test.json | 6 +
packages/agent-toolkit/tsup.config.ts | 23 ++
packages/backend/src/api/resources/User.ts | 10 +-
pnpm-lock.yaml | 263 +++++++++++++++++-
22 files changed, 1018 insertions(+), 9 deletions(-)
create mode 100644 .changeset/many-pumpkins-double.md
create mode 100644 packages/agent-toolkit/LICENSE
create mode 100644 packages/agent-toolkit/README.md
create mode 100644 packages/agent-toolkit/package.json
create mode 100644 packages/agent-toolkit/src/ai-sdk/adapter.ts
create mode 100644 packages/agent-toolkit/src/ai-sdk/index.ts
create mode 100644 packages/agent-toolkit/src/global.d.ts
create mode 100644 packages/agent-toolkit/src/langchain/adapter.ts
create mode 100644 packages/agent-toolkit/src/langchain/index.ts
create mode 100644 packages/agent-toolkit/src/lib/clerk-client.ts
create mode 100644 packages/agent-toolkit/src/lib/clerk-tool.ts
create mode 100644 packages/agent-toolkit/src/lib/constants.ts
create mode 100644 packages/agent-toolkit/src/lib/inject-session-claims.ts
create mode 100644 packages/agent-toolkit/src/lib/tools/index.ts
create mode 100644 packages/agent-toolkit/src/lib/tools/user-tools.ts
create mode 100644 packages/agent-toolkit/src/lib/types.ts
create mode 100644 packages/agent-toolkit/src/lib/utils.ts
create mode 100644 packages/agent-toolkit/tsconfig.json
create mode 100644 packages/agent-toolkit/tsconfig.test.json
create mode 100644 packages/agent-toolkit/tsup.config.ts
diff --git a/.changeset/many-pumpkins-double.md b/.changeset/many-pumpkins-double.md
new file mode 100644
index 00000000000..4e4866446f8
--- /dev/null
+++ b/.changeset/many-pumpkins-double.md
@@ -0,0 +1,8 @@
+---
+'@clerk/agent-toolkit': patch
+'@clerk/backend': patch
+---
+
+Introduce @clerk/agent-toolkit package. The Clerk Agent Toolkit enables popular agent frameworks, including Vercel's AI SDK and LangChain, to integrate with Clerk using tools (also known as function calling).
+
+This package exposes a subset of Clerk's functionality to agent frameworks, allowing you to build powerful agentic systems capable of managing users, user data, organizations, and more.
diff --git a/packages/agent-toolkit/LICENSE b/packages/agent-toolkit/LICENSE
new file mode 100644
index 00000000000..66914b6af7c
--- /dev/null
+++ b/packages/agent-toolkit/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Clerk, Inc.
+
+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/packages/agent-toolkit/README.md b/packages/agent-toolkit/README.md
new file mode 100644
index 00000000000..dddab065a8c
--- /dev/null
+++ b/packages/agent-toolkit/README.md
@@ -0,0 +1,230 @@
+
+
+
+
+
+
+
+
+
@clerk/agent-toolkit
+
+
+
+
+[](https://clerk.com/discord)
+[](https://clerk.com/docs?utm_source=github&utm_medium=clerk_agent_toolkit)
+[](https://twitter.com/intent/follow?screen_name=ClerkDev)
+
+[Changelog](https://github.com/clerk/javascript/blob/main/packages/agent-toolkit/CHANGELOG.md)
+·
+[Report a Bug](https://github.com/clerk/javascript/issues/new?assignees=&labels=needs-triage&projects=&template=BUG_REPORT.yml)
+·
+[Request a Feature](https://feedback.clerk.com/roadmap)
+·
+[Get Help](https://clerk.com/contact/support?utm_source=github&utm_medium=clerk_agent_toolkit)
+
+
+
+> ℹ️ Developer Preview
+>
+> Agent behavior is typically non-deterministic. Ensure you thoroughly test your integration and evaluate your application's performance. Additionally, consider scoping this toolkit's tools to specific users to limit resource access.
+>
+> If your app's code path is predetermined, it's always preferable to call APIs directly instead of using agents and tool calling.
+>
+> This SDK is recommended for testing purposes only unless you are confident in the agent's behavior and have implemented necessary security measures such as guardrails and best practices.
+
+## Table of Contents
+1. [Getting Started](#getting-started)
+2. [Public APIs](#public-apis)
+3. [Use with Vercel's AI SDK](#use-with-vercels-ai-sdk)
+4. [Use with Langchain](#use-with-langchain)
+5. [Advanced Usage](#advanced-usage)
+6. [Support](#support)
+
+## Getting Started
+
+Use this SDK to integrate [Clerk](https://clerk.com/?utm_source=github&utm_medium=clerk_agent_toolkit) into your agentic workflows. The Clerk Agent Toolkit enables popular agent frameworks, including Vercel's AI SDK and LangChain, to integrate with Clerk using tools (also known as function calling).
+
+This package exposes a subset of Clerk's functionality to agent frameworks, allowing you to build powerful agentic systems capable of managing users, user data, organizations, and more.
+
+## Public APIs
+
+The Clerk Agent Toolkit package provides two main import paths:
+
+- `@clerk/agent-toolkit/ai-sdk`: Helpers for integrating with Vercel's AI SDK.
+- `@clerk/agent-toolkit/langchain`: Helpers for integrating with Langchain.
+
+The toolkit offers the same tools and core APIs across frameworks, but their public interfaces may vary slightly to align with each framework's design:
+
+- `createClerkToolkit(options)`: Instantiates a new Clerk toolkit.
+- `toolkit.injectSessionClaims(systemPrompt)`: Injects session claims (userId, sessionId, orgId, etc.) into the system prompt, making them accessible to the AI model.
+- `toolkit.users()`: Provides tools for managing users.
+- `toolkit.organizations()`: Provides tools for managing organizations.
+- `toolkit.allTools()`: Returns all available tools.
+- `toolkit.toolMap()`: **(Langchain only)** Returns an object mapping available tools, useful for calling tools by name.
+
+For more details on each tool, refer to the framework-specific directories or the [Clerk BAPI documentation](https://clerk.com/docs/reference/backend-api).
+
+### Prerequisites
+- `ai-sdk`: `"^3.4.7 || ^4.0.0"`, or `langchain`: `"^0.3.6"`
+- A Clerk application
+- An API key for an AI model compatible with Langchain
+
+### Example Repository
+- [Clerk AI SDK Example](https://github.com/clerk/agent-toolkit-example)
+
+## Use with Vercel's AI SDK
+
+1. Install the Clerk Agent Toolkit package:
+
+ ```shell
+ npm install @clerk/agent-toolkit
+ ```
+
+2. Set the Clerk secret key as an environment variable in your project. Ensure you also configure any required LLM model keys.
+
+ ```
+ CLERK_SECRET_KEY=sk_
+ ```
+
+3. Import the helper from the `/ai-sdk` path, instantiate a new Clerk `toolkit`, and use it in your agent function:
+
+```typescript
+// Import the helper from the ai-sdk path
+import { createClerkToolkit } from "@clerk/agent-toolkit/ai-sdk";
+import { openai } from "@ai-sdk/openai";
+import { streamText } from "ai";
+import { auth } from "@clerk/nextjs/server";
+import { systemPrompt } from "@/lib/ai/prompts";
+
+export const maxDuration = 30;
+
+export async function POST(req: Request) {
+ const { messages } = await req.json();
+ // Optional - get the userId from the request
+ const { userId } = await auth.protect();
+
+ // Instantiate a new Clerk toolkit
+ // Optional - scope the toolkit to a specific user
+ const toolkit = await createClerkToolkit({ context: { userId } });
+
+ const result = streamText({
+ model: openai("gpt-4o"),
+ messages,
+ // Optional - inject session claims into the system prompt
+ system: toolkit.injectSessionClaims(systemPrompt),
+ tools: {
+ // Provide the tools you want to use
+ ...toolkit.users(),
+ ...toolkit.organizations(),
+ },
+ });
+
+ return result.toDataStreamResponse();
+}
+```
+
+## Use with Langchain
+
+
+
+1. Install the Clerk Agent Toolkit package:
+
+ ```shell
+ npm install @clerk/agent-toolkit
+ ```
+
+2. Set the Clerk secret key as an environment variable:
+
+ ```shell
+ CLERK_SECRET_KEY=sk_
+ ```
+
+3. Import the helper from the `/langchain` path, instantiate a new Clerk `toolkit`, and use it in your agent function:
+
+```typescript
+// Import the helper from the langchain path
+import { createClerkToolkit } from "@clerk/agent-toolkit/langchain";
+import { ChatOpenAI } from "@langchain/openai";
+import { auth } from "@clerk/nextjs/server";
+import { HumanMessage, SystemMessage } from "@langchain/core/messages";
+import { LangChainAdapter } from "ai";
+import { systemPrompt } from "@/lib/ai/prompts";
+
+export const maxDuration = 30;
+
+export async function POST(req: Request) {
+ const { prompt } = await req.json();
+ const { userId } = await auth.protect();
+
+ // Instantiate a new Clerk toolkit
+ // Optional - scope the toolkit to a specific user
+ const toolkit = await createClerkToolkit({ context: { userId } });
+
+ const model = new ChatOpenAI({ model: "gpt-4o", temperature: 0 });
+
+ // Bind the tools you want to use to the model
+ const modelWithTools = model.bindTools(toolkit.users());
+
+ const messages = [new SystemMessage(toolkit.injectSessionClaims(systemPrompt)), new HumanMessage(prompt)];
+ const aiMessage = await modelWithTools.invoke(messages);
+ messages.push(aiMessage);
+
+ for (const toolCall of aiMessage.tool_calls || []) {
+ // Call the selected tool
+ const selectedTool = toolkit.toolMap()[toolCall.name];
+ const toolMessage = await selectedTool.invoke(toolCall);
+ messages.push(toolMessage);
+ }
+
+ // To simplify the setup, this example uses the ai-sdk langchain adapter
+ // to stream the results back to the /langchain page.
+ // For more details, see: https://sdk.vercel.ai/providers/adapters/langchain
+ const stream = await modelWithTools.stream(messages);
+ return LangChainAdapter.toDataStreamResponse(stream);
+}
+
+````
+
+## Advanced Usage
+
+### Using a Custom `clerkClient`
+
+If you need to set the Clerk secret key dynamically or use different Clerk instances, pass a custom `clerkClient`:
+
+```typescript
+import { createClerkToolkit } from "@clerk/agent-toolkit/ai-sdk";
+import { createClerkClient } from "@clerk/backend";
+
+export async function POST(req: Request) {
+ // Create a new Clerk client
+ const clerkClient = createClerkClient({ secretKey: "sk_" });
+
+ // Instantiate a new Clerk toolkit with the custom client
+ const toolkit = await createClerkToolkit({ clerkClient });
+
+ // Use the toolkit as usual
+ const result = streamText({
+ model: openai("gpt-4o"),
+ messages,
+ tools: toolkit.users()
+ });
+}
+```
+
+## Support
+
+You can get in touch with us in any of the following ways:
+
+- Join our official community [Discord server](https://clerk.com/discord)
+- On [our support page](https://clerk.com/contact/support?utm_source=github&utm_medium=clerk_agent_toolkit)
+
+## Contributing
+
+We're open to all community contributions! If you'd like to contribute in any way, please read [our contribution guidelines](https://github.com/clerk/javascript/blob/main/docs/CONTRIBUTING.md) and [code of conduct](https://github.com/clerk/javascript/blob/main/docs/CODE_OF_CONDUCT.md).
+
+## License
+
+This project is licensed under the **MIT license**.
+
+See [LICENSE](https://github.com/clerk/javascript/blob/main/packages/agent-toolkit/LICENSE) for more information.
diff --git a/packages/agent-toolkit/package.json b/packages/agent-toolkit/package.json
new file mode 100644
index 00000000000..d94e777a4e6
--- /dev/null
+++ b/packages/agent-toolkit/package.json
@@ -0,0 +1,66 @@
+{
+ "name": "@clerk/agent-toolkit",
+ "version": "0.0.1",
+ "private": true,
+ "description": "Clerk Toolkit for AI Agents",
+ "homepage": "https://clerk.com/",
+ "bugs": {
+ "url": "https://github.com/clerk/javascript/issues"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/clerk/javascript.git",
+ "directory": "packages/agent-toolkit"
+ },
+ "license": "MIT",
+ "author": "Clerk",
+ "sideEffects": false,
+ "files": [
+ "dist"
+ ],
+ "exports": {
+ "./langchain": {
+ "types": "./dist/langchain/index.d.ts",
+ "require": "./dist/langchain/index.js",
+ "import": "./dist/langchain/index.mjs"
+ },
+ "./ai-sdk": {
+ "types": "./dist/ai-sdk/index.d.ts",
+ "require": "./dist/ai-sdk/index.js",
+ "import": "./dist/ai-sdk/index.mjs"
+ }
+ },
+ "scripts": {
+ "build": "tsup --env.NODE_ENV production",
+ "clean": "rimraf ./dist",
+ "dev": "tsup --watch",
+ "lint": "eslint src",
+ "lint:attw": "attw --pack .",
+ "lint:publint": "publint",
+ "test:cache:clear": "jest --clearCache --useStderr"
+ },
+ "dependencies": {
+ "@clerk/backend": "workspace:^",
+ "@clerk/shared": "workspace:^",
+ "@clerk/types": "workspace:^",
+ "zod": "^3.24.1"
+ },
+ "peerDependencies": {
+ "@langchain/core": "^0.3.6",
+ "ai": "^3.4.7 || ^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@langchain/core": {
+ "optional": true
+ },
+ "ai": {
+ "optional": true
+ }
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/packages/agent-toolkit/src/ai-sdk/adapter.ts b/packages/agent-toolkit/src/ai-sdk/adapter.ts
new file mode 100644
index 00000000000..b9ae77033f7
--- /dev/null
+++ b/packages/agent-toolkit/src/ai-sdk/adapter.ts
@@ -0,0 +1,12 @@
+import type { Tool } from 'ai';
+import { tool } from 'ai';
+
+import type { SdkAdapter } from '../lib/types';
+
+export const adapter: SdkAdapter = (clerkClient, context, clerkTool) => {
+ return tool({
+ description: clerkTool.description,
+ parameters: clerkTool.parameters,
+ execute: clerkTool.bindRunnable(clerkClient, context),
+ });
+};
diff --git a/packages/agent-toolkit/src/ai-sdk/index.ts b/packages/agent-toolkit/src/ai-sdk/index.ts
new file mode 100644
index 00000000000..7ad9a86bf1c
--- /dev/null
+++ b/packages/agent-toolkit/src/ai-sdk/index.ts
@@ -0,0 +1,43 @@
+import { clerkClient as _clerkClient } from '../lib/clerk-client';
+import { defaultToolkitContext } from '../lib/constants';
+import { injectSessionClaims } from '../lib/inject-session-claims';
+import { flatTools, tools } from '../lib/tools';
+import type { ClerkToolkitBase, CreateClerkToolkitParams } from '../lib/types';
+import { shallowTransform } from '../lib/utils';
+import { adapter } from './adapter';
+
+export type ClerkToolkit = ClerkToolkitBase & {
+ /**
+ * Returns an object with all the tools from all categories in the Clerk toolkit.
+ *
+ * Most LLM providers recommend that for each LLM call, the number of available tools should be kept to a minimum,
+ * usually around 10-20 tools. This increases the LLM's accuracy when picking the right tool.
+ *
+ * As a result, we also recommend to use the fine-grained tool categories, for example, `toolkit.users` instead.
+ */
+ allTools: () => { [key in keyof typeof flatTools]: ReturnType };
+} & {
+ [key in keyof typeof tools]: () => { [tool in keyof (typeof tools)[key]]: ReturnType };
+};
+
+export const createClerkToolkit = async (params: CreateClerkToolkitParams = {}): Promise => {
+ const clerkClient = params.clerkClient || _clerkClient;
+ const context = params.context || defaultToolkitContext;
+
+ const adaptedTools = shallowTransform(tools, toolSection => {
+ return () =>
+ shallowTransform(toolSection, t => {
+ return adapter(clerkClient, context, t);
+ });
+ });
+
+ const allTools = () => {
+ return shallowTransform(flatTools, t => adapter(clerkClient, context, t));
+ };
+
+ return {
+ ...adaptedTools,
+ allTools,
+ injectSessionClaims: injectSessionClaims(context),
+ };
+};
diff --git a/packages/agent-toolkit/src/global.d.ts b/packages/agent-toolkit/src/global.d.ts
new file mode 100644
index 00000000000..1ae75219e34
--- /dev/null
+++ b/packages/agent-toolkit/src/global.d.ts
@@ -0,0 +1,6 @@
+declare global {
+ const PACKAGE_NAME: string;
+ const PACKAGE_VERSION: string;
+}
+
+export {};
diff --git a/packages/agent-toolkit/src/langchain/adapter.ts b/packages/agent-toolkit/src/langchain/adapter.ts
new file mode 100644
index 00000000000..85bce7461eb
--- /dev/null
+++ b/packages/agent-toolkit/src/langchain/adapter.ts
@@ -0,0 +1,13 @@
+import type { StructuredTool } from '@langchain/core/tools';
+import { tool } from '@langchain/core/tools';
+
+import type { SdkAdapter } from '../lib/types';
+
+// https://js.langchain.com/docs/how_to/custom_tools
+export const adapter: SdkAdapter = (clerkClient, context, clerkTool) => {
+ return tool(clerkTool.bindRunnable(clerkClient, context), {
+ name: clerkTool.name,
+ description: clerkTool.description,
+ schema: clerkTool.parameters,
+ });
+};
diff --git a/packages/agent-toolkit/src/langchain/index.ts b/packages/agent-toolkit/src/langchain/index.ts
new file mode 100644
index 00000000000..f2c6e0099e1
--- /dev/null
+++ b/packages/agent-toolkit/src/langchain/index.ts
@@ -0,0 +1,48 @@
+import { clerkClient as _clerkClient } from '../lib/clerk-client';
+import { defaultToolkitContext } from '../lib/constants';
+import { injectSessionClaims } from '../lib/inject-session-claims';
+import { flatTools, tools } from '../lib/tools';
+import type { ClerkToolkitBase, CreateClerkToolkitParams } from '../lib/types';
+import { shallowTransform } from '../lib/utils';
+import { adapter } from './adapter';
+
+export type ClerkToolkit = ClerkToolkitBase & {
+ /**
+ * Returns an array containing all tools from all categories in the Clerk toolkit.
+ *
+ * Most LLM providers recommend that for each LLM call, the number of available tools should be kept to a minimum,
+ * usually around 10-20 tools. This increases the LLM's accuracy when picking the right tool.
+ *
+ * As a result, we also recommend to use the fine-grained tool categories, for example, `toolkit.users` instead.
+ */
+ allTools: () => Array>;
+ /**
+ * Returns an object with all the tools from all categories in the Clerk toolkit.
+ * Useful when using tool calling with Langchain messages (e.g. `tool_calls`).
+ */
+ toolMap: () => { [key in keyof typeof flatTools]: ReturnType };
+} & {
+ [key in keyof typeof tools]: () => Array>;
+};
+
+export const createClerkToolkit = async (params: CreateClerkToolkitParams = {}): Promise => {
+ const clerkClient = params.clerkClient || _clerkClient;
+ const context = params.context || defaultToolkitContext;
+
+ const adaptedTools = shallowTransform(tools, toolSection => {
+ return () => Object.values(toolSection).map(t => adapter(clerkClient, context, t));
+ });
+
+ const allTools = () => {
+ return Object.values(flatTools).map(t => adapter(clerkClient, context, t));
+ };
+
+ const toolMap = shallowTransform(flatTools, t => adapter(clerkClient, context, t));
+
+ return {
+ ...adaptedTools,
+ allTools,
+ toolMap: () => toolMap,
+ injectSessionClaims: injectSessionClaims(context),
+ };
+};
diff --git a/packages/agent-toolkit/src/lib/clerk-client.ts b/packages/agent-toolkit/src/lib/clerk-client.ts
new file mode 100644
index 00000000000..5b709e713ad
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/clerk-client.ts
@@ -0,0 +1,22 @@
+import { createClerkClient } from '@clerk/backend';
+import { apiUrlFromPublishableKey } from '@clerk/shared/apiUrlFromPublishableKey';
+
+const API_VERSION = process.env.CLERK_API_VERSION || 'v1';
+const SECRET_KEY = process.env.CLERK_SECRET_KEY || '';
+const PUBLISHABLE_KEY = process.env.CLERK_PUBLISHABLE_KEY || '';
+const API_URL = process.env.CLERK_API_URL || apiUrlFromPublishableKey(PUBLISHABLE_KEY);
+const JWT_KEY = process.env.CLERK_JWT_KEY || '';
+const SDK_METADATA = {
+ name: PACKAGE_NAME,
+ version: PACKAGE_VERSION,
+ environment: process.env.NODE_ENV,
+};
+
+export const clerkClient = createClerkClient({
+ secretKey: SECRET_KEY,
+ apiUrl: API_URL,
+ apiVersion: API_VERSION,
+ jwtKey: JWT_KEY,
+ userAgent: `${PACKAGE_NAME}@${PACKAGE_VERSION}`,
+ sdkMetadata: SDK_METADATA,
+});
diff --git a/packages/agent-toolkit/src/lib/clerk-tool.ts b/packages/agent-toolkit/src/lib/clerk-tool.ts
new file mode 100644
index 00000000000..8c82b5c6d82
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/clerk-tool.ts
@@ -0,0 +1,55 @@
+import type { ClerkClient } from '@clerk/backend';
+import type { ZodObject } from 'zod';
+
+import type { ToolkitContext } from './types';
+
+export interface ClerkTool {
+ /**
+ * The name of the tool. This can be used to reference the tool in the code.
+ * A descriptive LLM-readable string.
+ */
+ name: string;
+ /**
+ * A descriptive prompt explaining the tool's purpose, usage and input parameters.
+ * Ths is intended to be used by the underlying LLM.
+ * To avoid duplication, the description can reference the parameters by using the `$parameters` prefix.
+ */
+ description: string;
+ /**
+ * The Zod schema for the input parameters of the tool
+ */
+ parameters: ZodObject;
+ /**
+ * The actual implementation of the tool.
+ */
+ bindRunnable: (clerkClient: ClerkClient, context: ToolkitContext) => (input: any) => Promise;
+}
+
+const trimLines = (text: string) =>
+ text
+ .split('\n')
+ .map(l => l.trim())
+ .filter(Boolean)
+ .join('\n');
+
+export const ClerkTool = (params: ClerkTool): ClerkTool => {
+ const schemaEntries = Object.entries(params.parameters.shape);
+ const args =
+ schemaEntries.length === 0
+ ? 'Takes no arguments'
+ : Object.entries(params.parameters.shape)
+ .map(([key, value]) => {
+ return `- ${key}: ${(value as any).description || ''}`;
+ })
+ .join('\n');
+
+ const description = trimLines(`
+ Tool name:
+ ${params.name}
+ Description:
+ ${params.description}.
+ Arguments:
+ ${args}
+ `);
+ return { ...params, description };
+};
diff --git a/packages/agent-toolkit/src/lib/constants.ts b/packages/agent-toolkit/src/lib/constants.ts
new file mode 100644
index 00000000000..7f23a9bdebe
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/constants.ts
@@ -0,0 +1,5 @@
+import type {ToolkitContext} from "./types";
+
+export const defaultToolkitContext: ToolkitContext = {
+ allowPrivateMetadata: false,
+};
diff --git a/packages/agent-toolkit/src/lib/inject-session-claims.ts b/packages/agent-toolkit/src/lib/inject-session-claims.ts
new file mode 100644
index 00000000000..db31cf5892e
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/inject-session-claims.ts
@@ -0,0 +1,18 @@
+import type { ToolkitContext } from './types';
+
+export const injectSessionClaims = (context: ToolkitContext) => (prompt: string) => {
+ if (!context.sessionClaims && !context.userId) {
+ return prompt;
+ }
+
+ const lines = [];
+ lines.push(`# Signed-in user info:`);
+ lines.push(
+ context.sessionClaims?.sub || context.userId
+ ? `Your userId is ${context.sessionClaims?.sub || context.userId}`
+ : '',
+ );
+ lines.push(context.sessionClaims?.sid ? `Your sessionId is ${context.sessionClaims?.sid}` : '');
+ lines.push(prompt);
+ return lines.filter(Boolean).join('\n');
+};
diff --git a/packages/agent-toolkit/src/lib/tools/index.ts b/packages/agent-toolkit/src/lib/tools/index.ts
new file mode 100644
index 00000000000..a7714fe5291
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/tools/index.ts
@@ -0,0 +1,15 @@
+import { users } from './user-tools';
+
+export const tools = {
+ /**
+ * Tools for interacting with users.
+ * This is a wrapper around the `clerkClient.users` API.
+ * For more information, see the [Clerk API documentation](https://clerk.com/docs/reference/backend-api/tag/Users).
+ */
+ users,
+} as const;
+
+// Just to help with types later on
+export const flatTools = {
+ ...users,
+};
diff --git a/packages/agent-toolkit/src/lib/tools/user-tools.ts b/packages/agent-toolkit/src/lib/tools/user-tools.ts
new file mode 100644
index 00000000000..76676aba762
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/tools/user-tools.ts
@@ -0,0 +1,52 @@
+import { z } from 'zod';
+
+import { ClerkTool } from '../clerk-tool';
+import { prunePrivateData } from '../utils';
+
+const getUserId = ClerkTool({
+ name: 'getUserId',
+ description: `
+ Get the userId of the current user if signed in, otherwise return null.
+ `,
+ parameters: z.object({}),
+ bindRunnable: (clerkClient, context) => () => {
+ return Promise.resolve(context.userId || null);
+ },
+});
+
+const getUser = ClerkTool({
+ name: 'getUser',
+ description: `
+ Retrieves information about a single User by their userId, if the userId is valid.
+ `,
+ parameters: z.object({
+ userId: z.string().describe('(string): The userId of the User to retrieve'),
+ }),
+ bindRunnable: (clerkClient, context) => async params => {
+ const res = await clerkClient.users.getUser(context.userId || params.userId);
+ return prunePrivateData(context, res.raw);
+ },
+});
+
+const updateUserPublicMetadata = ClerkTool({
+ name: 'updateUserPublicMetadata',
+ description: `
+ Updates the public metadata associated with the specified user by merging existing values with the provided parameters.
+ A "deep" merge will be performed - "deep" means that any nested JSON objects will be merged as well. You can remove metadata keys at any level by setting their value to null.
+ `,
+ parameters: z.object({
+ userId: z.string().describe('(string): The userId of the User to update'),
+ metadata: z.record(z.string(), z.any()).describe('(Record): The new public metadata to set'),
+ }),
+ bindRunnable: (clerkClient, context) => async params => {
+ const { userId, metadata } = params;
+ const res = await clerkClient.users.updateUserMetadata(context.userId || userId, { publicMetadata: metadata });
+ return prunePrivateData(context, res.raw);
+ },
+});
+
+export const users = {
+ getUserId,
+ getUser,
+ updateUserPublicMetadata,
+} as const;
diff --git a/packages/agent-toolkit/src/lib/types.ts b/packages/agent-toolkit/src/lib/types.ts
new file mode 100644
index 00000000000..1c458013db4
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/types.ts
@@ -0,0 +1,26 @@
+import type { ClerkClient } from '@clerk/backend';
+import type { SignedInAuthObject } from '@clerk/backend/internal';
+
+import type { ClerkTool } from './clerk-tool';
+
+export type SdkAdapter = (clerkClient: ClerkClient, context: ToolkitContext, clerkTool: ClerkTool) => T;
+
+export type ToolkitContext = {
+ userId?: string;
+ sessionClaims?: SignedInAuthObject['sessionClaims'];
+ allowPrivateMetadata?: boolean;
+};
+
+export type CreateClerkToolkitParams = {
+ clerkClient?: ClerkClient;
+ context?: ToolkitContext;
+};
+
+export type ClerkToolkitBase = {
+ /**
+ * Augment the system prompt with data about the current session.
+ * This usually contains the userId, the sessionId, the organizationId, etc.
+ * This property uses the data passed to `createClerkToolkit`.
+ */
+ injectSessionClaims: (prompt: string) => string;
+};
diff --git a/packages/agent-toolkit/src/lib/utils.ts b/packages/agent-toolkit/src/lib/utils.ts
new file mode 100644
index 00000000000..2400130332f
--- /dev/null
+++ b/packages/agent-toolkit/src/lib/utils.ts
@@ -0,0 +1,66 @@
+import type { ToolkitContext } from './types';
+
+// A helper type that maps T to a new type with every leaf replaced by R.
+type DeepTransform =
+ T extends Array ? DeepTransform[] : T extends object ? { [K in keyof T]: DeepTransform } : R;
+
+/**
+ * Recursively transforms every value in an object (or array) by applying a function.
+ *
+ * The result has the same structure as the input object,
+ but each leaf value is replaced with the return type R of the transform function.
+ */
+export function deepTransform(input: T, transformFn: (value: any) => R): DeepTransform {
+ if (Array.isArray(input)) {
+ // Recursively transform each element of the array.
+ return input.map(item => deepTransform(item, transformFn)) as DeepTransform;
+ } else if (input !== null && typeof input === 'object') {
+ // Recursively transform each property of the object.
+ const result: any = {};
+ for (const key in input) {
+ if (Object.prototype.hasOwnProperty.call(input, key)) {
+ result[key] = deepTransform((input as any)[key], transformFn);
+ }
+ }
+ return result as DeepTransform;
+ } else {
+ // For non-objects, apply the transform function.
+ return transformFn(input) as DeepTransform;
+ }
+}
+
+/**
+ * A mapped type that replaces every property in T with type R.
+ */
+type ShallowTransform = {
+ [K in keyof T]: R;
+};
+
+/**
+ * Transforms the top-level values of an object using a transformation function.
+ *
+ */
+export function shallowTransform(
+ input: T,
+ transformFn: (value: T[keyof T]) => R,
+): ShallowTransform {
+ const result = {} as ShallowTransform;
+ for (const key in input) {
+ if (Object.prototype.hasOwnProperty.call(input, key)) {
+ const typedKey = key as keyof T;
+ result[typedKey] = transformFn(input[typedKey]);
+ }
+ }
+ return result;
+}
+
+export const prunePrivateData = (context: ToolkitContext, o?: Record | null) => {
+ if (context.allowPrivateMetadata) {
+ return o;
+ }
+
+ if (o && o.private_metadata) {
+ delete o.private_metadata;
+ }
+ return o;
+};
diff --git a/packages/agent-toolkit/tsconfig.json b/packages/agent-toolkit/tsconfig.json
new file mode 100644
index 00000000000..57b39d50251
--- /dev/null
+++ b/packages/agent-toolkit/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "moduleResolution": "NodeNext",
+ "module": "NodeNext",
+ "sourceMap": false,
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "allowJs": true,
+ "target": "ES2020",
+ "emitDeclarationOnly": true,
+ "declaration": true,
+ "declarationMap": true,
+ "outDir": "dist",
+ "resolveJsonModule": true,
+ "declarationDir": "dist/types"
+ },
+ "include": ["src"]
+}
diff --git a/packages/agent-toolkit/tsconfig.test.json b/packages/agent-toolkit/tsconfig.test.json
new file mode 100644
index 00000000000..5635d6cd1b7
--- /dev/null
+++ b/packages/agent-toolkit/tsconfig.test.json
@@ -0,0 +1,6 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "sourceMap": true
+ }
+}
diff --git a/packages/agent-toolkit/tsup.config.ts b/packages/agent-toolkit/tsup.config.ts
new file mode 100644
index 00000000000..7eb4dadc8e0
--- /dev/null
+++ b/packages/agent-toolkit/tsup.config.ts
@@ -0,0 +1,23 @@
+import { defineConfig } from 'tsup';
+
+import { name, version } from './package.json';
+
+export default defineConfig(overrideOptions => {
+ const isProd = overrideOptions.env?.NODE_ENV === 'production';
+
+ return {
+ entry: ['src/ai-sdk/index.ts', 'src/langchain/index.ts'],
+ dts: true,
+ // onSuccess: 'tsc',
+ minify: isProd,
+ clean: true,
+ sourcemap: true,
+ format: ['cjs', 'esm'],
+ // legacyOutput: true,
+ define: {
+ PACKAGE_NAME: `"${name}"`,
+ PACKAGE_VERSION: `"${version}"`,
+ __DEV__: `${!isProd}`,
+ },
+ };
+});
diff --git a/packages/backend/src/api/resources/User.ts b/packages/backend/src/api/resources/User.ts
index f70b7da959a..5da7b6a97ef 100644
--- a/packages/backend/src/api/resources/User.ts
+++ b/packages/backend/src/api/resources/User.ts
@@ -6,6 +6,12 @@ import { SamlAccount } from './SamlAccount';
import { Web3Wallet } from './Web3Wallet';
export class User {
+ private _raw: UserJSON | null = null;
+
+ public get raw(): UserJSON | null {
+ return this._raw;
+ }
+
constructor(
readonly id: string,
readonly passwordEnabled: boolean,
@@ -42,7 +48,7 @@ export class User {
) {}
static fromJSON(data: UserJSON): User {
- return new User(
+ const res = new User(
data.id,
data.password_enabled,
data.totp_enabled,
@@ -76,6 +82,8 @@ export class User {
data.delete_self_enabled,
data.legal_accepted_at,
);
+ res._raw = data;
+ return res;
}
get primaryEmailAddress() {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6f58ebff3d5..f109f9a60cb 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -302,6 +302,27 @@ importers:
specifier: catalog:repo
version: 8.3.0
+ packages/agent-toolkit:
+ dependencies:
+ '@clerk/backend':
+ specifier: workspace:^
+ version: link:../backend
+ '@clerk/shared':
+ specifier: workspace:^
+ version: link:../shared
+ '@clerk/types':
+ specifier: workspace:^
+ version: link:../types
+ '@langchain/core':
+ specifier: ^0.3.6
+ version: 0.3.39
+ ai:
+ specifier: ^3.4.7 || ^4.0.0
+ version: 4.1.34(react@18.3.1)(zod@3.24.1)
+ zod:
+ specifier: ^3.24.1
+ version: 3.24.1
+
packages/astro:
dependencies:
'@clerk/backend':
@@ -541,7 +562,7 @@ importers:
version: 8.2.2
next:
specifier: ^14.2.23
- version: 14.2.23(@babel/core@7.26.7)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 14.2.23(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
type-fest:
specifier: ^4.33.0
version: 4.33.0
@@ -710,7 +731,7 @@ importers:
version: 4.2.2
next:
specifier: ^14.2.23
- version: 14.2.23(@babel/core@7.26.7)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 14.2.23(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
packages/nuxt:
dependencies:
@@ -1150,6 +1171,40 @@ packages:
'@adobe/css-tools@4.4.0':
resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==}
+ '@ai-sdk/provider-utils@2.1.6':
+ resolution: {integrity: sha512-Pfyaj0QZS22qyVn5Iz7IXcJ8nKIKlu2MeSAdKJzTwkAks7zdLaKVB+396Rqcp1bfQnxl7vaduQVMQiXUrgK8Gw==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ zod: ^3.0.0
+ peerDependenciesMeta:
+ zod:
+ optional: true
+
+ '@ai-sdk/provider@1.0.7':
+ resolution: {integrity: sha512-q1PJEZ0qD9rVR+8JFEd01/QM++csMT5UVwYXSN2u54BrVw/D8TZLTeg2FEfKK00DgAx0UtWd8XOhhwITP9BT5g==}
+ engines: {node: '>=18'}
+
+ '@ai-sdk/react@1.1.11':
+ resolution: {integrity: sha512-vfjZ7w2M+Me83HTMMrnnrmXotz39UDCMd27YQSrvt2f1YCLPloVpLhP+Y9TLZeFE/QiiRCrPYLDQm6aQJYJ9PQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ react: ^18 || ^19 || ^19.0.0-rc
+ zod: ^3.0.0
+ peerDependenciesMeta:
+ react:
+ optional: true
+ zod:
+ optional: true
+
+ '@ai-sdk/ui-utils@1.1.11':
+ resolution: {integrity: sha512-1SC9W4VZLcJtxHRv4Y0aX20EFeaEP6gUvVqoKLBBtMLOgtcZrv/F/HQRjGavGugiwlS3dsVza4X+E78fiwtlTA==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ zod: ^3.0.0
+ peerDependenciesMeta:
+ zod:
+ optional: true
+
'@alcalzone/ansi-tokenize@0.1.3':
resolution: {integrity: sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw==}
engines: {node: '>=14.13.1'}
@@ -1976,6 +2031,9 @@ packages:
'@bundled-es-modules/tough-cookie@0.1.6':
resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==}
+ '@cfworker/json-schema@4.1.1':
+ resolution: {integrity: sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==}
+
'@changesets/apply-release-plan@7.0.5':
resolution: {integrity: sha512-1cWCk+ZshEkSVEZrm2fSj1Gz8sYvxgUL4Q78+1ZZqeqfuevPTPk033/yUZ3df8BKMohkqqHfzj0HOOrG0KtXTw==}
@@ -3289,6 +3347,10 @@ packages:
'@kwsites/promise-deferred@1.1.1':
resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==}
+ '@langchain/core@0.3.39':
+ resolution: {integrity: sha512-muXs4asy1A7qDtcdznxqyBfxf4N6qxofY/S0c95vbsWa0r9YAE2PttHIjcuxSy1q2jUiTkpCcgFEjNJRQRVhEw==}
+ engines: {node: '>=18'}
+
'@leichtgewicht/ip-codec@2.0.4':
resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==}
@@ -3582,6 +3644,10 @@ packages:
'@open-draft/until@2.1.0':
resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
+ '@opentelemetry/api@1.9.0':
+ resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
+ engines: {node: '>=8.0.0'}
+
'@oslojs/encoding@1.1.0':
resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
@@ -5385,6 +5451,9 @@ packages:
'@types/debug@4.1.12':
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
+ '@types/diff-match-patch@1.0.36':
+ resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==}
+
'@types/diff@6.0.0':
resolution: {integrity: sha512-dhVCYGv3ZSbzmQaBSagrv1WJ6rXCdkyTcDyoNu1MD8JohI7pR7k8wdZEm+mvdxRKXyHVwckFzWU1vJc+Z29MlA==}
@@ -5574,6 +5643,9 @@ packages:
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
+ '@types/uuid@10.0.0':
+ resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==}
+
'@types/webextension-polyfill@0.10.7':
resolution: {integrity: sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==}
@@ -6090,6 +6162,18 @@ packages:
resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==}
engines: {node: '>=12'}
+ ai@4.1.34:
+ resolution: {integrity: sha512-9IB5duz6VbXvjibqNrvKz6++PwE8Ui5UfbOC9/CtcQN5Z9sudUQErss+maj7ptoPysD2NPjj99e0Hp183Cz5LQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ react: ^18 || ^19 || ^19.0.0-rc
+ zod: ^3.0.0
+ peerDependenciesMeta:
+ react:
+ optional: true
+ zod:
+ optional: true
+
ajv-formats@2.1.1:
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
@@ -7128,6 +7212,9 @@ packages:
resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==}
engines: {node: ^14.18.0 || >=16.10.0}
+ console-table-printer@2.12.1:
+ resolution: {integrity: sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==}
+
content-disposition@0.5.4:
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
engines: {node: '>= 0.6'}
@@ -7723,6 +7810,9 @@ packages:
didyoumean@1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
+ diff-match-patch@1.0.5:
+ resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==}
+
diff-sequences@29.6.3:
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -8253,6 +8343,10 @@ packages:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
+ eventsource-parser@3.0.0:
+ resolution: {integrity: sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==}
+ engines: {node: '>=18.0.0'}
+
exec-async@2.2.0:
resolution: {integrity: sha512-87OpwcEiMia/DeiKFzaQNBNFeN3XkkpYIh9FyOqq5mS2oKv3CBE67PXoEKcr6nodWdXNogTiQ0jE2NGuoffXPw==}
@@ -9979,6 +10073,9 @@ packages:
resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==}
engines: {node: '>=0.10.0'}
+ js-tiktoken@1.0.18:
+ resolution: {integrity: sha512-hFYx4xYf6URgcttcGvGuOBJhTxPYZ2R5eIesqCaNRJmYH8sNmsfTeWg4yu//7u1VD/qIUkgKJTpGom9oHXmB4g==}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -10107,6 +10204,11 @@ packages:
engines: {node: '>=6'}
hasBin: true
+ jsondiffpatch@0.6.0:
+ resolution: {integrity: sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+
jsonfile@4.0.0:
resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
@@ -10172,6 +10274,14 @@ packages:
kolorist@1.8.0:
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
+ langsmith@0.3.7:
+ resolution: {integrity: sha512-wakN1hxGkm1JR2PpAV7fiT7oC99LKcgxiuUrYGZWPbuj7Y8EPF19F7VNr4B+hA219bfaeWTa4Lxy2YrtPSKnQA==}
+ peerDependencies:
+ openai: '*'
+ peerDependenciesMeta:
+ openai:
+ optional: true
+
language-subtag-registry@0.3.23:
resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==}
@@ -10987,6 +11097,10 @@ packages:
resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==}
hasBin: true
+ mustache@4.2.0:
+ resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
+ hasBin: true
+
mute-stream@2.0.0:
resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==}
engines: {node: ^18.17.0 || >=20.5.0}
@@ -11489,6 +11603,10 @@ packages:
resolution: {integrity: sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==}
engines: {node: '>=16'}
+ p-queue@6.6.2:
+ resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==}
+ engines: {node: '>=8'}
+
p-queue@8.0.1:
resolution: {integrity: sha512-NXzu9aQJTAzbBqOt2hwsR63ea7yvxJc0PwN/zobNAudYfb1B7R08SzB4TsLeSbUCuG467NhnoT0oO6w1qRO+BA==}
engines: {node: '>=18'}
@@ -11501,6 +11619,10 @@ packages:
resolution: {integrity: sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==}
engines: {node: '>=16.17'}
+ p-timeout@3.2.0:
+ resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==}
+ engines: {node: '>=8'}
+
p-timeout@5.1.0:
resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==}
engines: {node: '>=12'}
@@ -12978,6 +13100,9 @@ packages:
simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+ simple-wcswidth@1.0.1:
+ resolution: {integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==}
+
sirv@1.0.19:
resolution: {integrity: sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==}
engines: {node: '>= 10'}
@@ -13597,6 +13722,10 @@ packages:
throttleit@1.0.1:
resolution: {integrity: sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==}
+ throttleit@2.1.0:
+ resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==}
+ engines: {node: '>=18'}
+
through2@2.0.5:
resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==}
@@ -14300,6 +14429,10 @@ packages:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'}
+ uuid@10.0.0:
+ resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
+ hasBin: true
+
uuid@7.0.3:
resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==}
hasBin: true
@@ -15057,10 +15190,10 @@ packages:
resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==}
engines: {node: '>= 14'}
- zod-to-json-schema@3.23.3:
- resolution: {integrity: sha512-TYWChTxKQbRJp5ST22o/Irt9KC5nj7CdBKYB/AosCRdj/wxEMvv4NNaj9XVUHDOIp53ZxArGhnw5HMZziPFjog==}
+ zod-to-json-schema@3.24.1:
+ resolution: {integrity: sha512-3h08nf3Vw3Wl3PK+q3ow/lIil81IT2Oa7YpQyUUDsEWbXveMesdfK1xBd2RhCkynwZndAxixji/7SYJJowr62w==}
peerDependencies:
- zod: ^3.23.3
+ zod: ^3.24.1
zod-to-ts@1.2.0:
resolution: {integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==}
@@ -15099,6 +15232,37 @@ snapshots:
'@adobe/css-tools@4.4.0': {}
+ '@ai-sdk/provider-utils@2.1.6(zod@3.24.1)':
+ dependencies:
+ '@ai-sdk/provider': 1.0.7
+ eventsource-parser: 3.0.0
+ nanoid: 3.3.8
+ secure-json-parse: 2.7.0
+ optionalDependencies:
+ zod: 3.24.1
+
+ '@ai-sdk/provider@1.0.7':
+ dependencies:
+ json-schema: 0.4.0
+
+ '@ai-sdk/react@1.1.11(react@18.3.1)(zod@3.24.1)':
+ dependencies:
+ '@ai-sdk/provider-utils': 2.1.6(zod@3.24.1)
+ '@ai-sdk/ui-utils': 1.1.11(zod@3.24.1)
+ swr: 2.2.5(react@18.3.1)
+ throttleit: 2.1.0
+ optionalDependencies:
+ react: 18.3.1
+ zod: 3.24.1
+
+ '@ai-sdk/ui-utils@1.1.11(zod@3.24.1)':
+ dependencies:
+ '@ai-sdk/provider': 1.0.7
+ '@ai-sdk/provider-utils': 2.1.6(zod@3.24.1)
+ zod-to-json-schema: 3.24.1(zod@3.24.1)
+ optionalDependencies:
+ zod: 3.24.1
+
'@alcalzone/ansi-tokenize@0.1.3':
dependencies:
ansi-styles: 6.2.1
@@ -16163,6 +16327,8 @@ snapshots:
'@types/tough-cookie': 4.0.5
tough-cookie: 4.1.4
+ '@cfworker/json-schema@4.1.1': {}
+
'@changesets/apply-release-plan@7.0.5':
dependencies:
'@changesets/config': 3.0.3
@@ -17729,6 +17895,23 @@ snapshots:
'@kwsites/promise-deferred@1.1.1': {}
+ '@langchain/core@0.3.39':
+ dependencies:
+ '@cfworker/json-schema': 4.1.1
+ ansi-styles: 5.2.0
+ camelcase: 6.3.0
+ decamelize: 1.2.0
+ js-tiktoken: 1.0.18
+ langsmith: 0.3.7
+ mustache: 4.2.0
+ p-queue: 6.6.2
+ p-retry: 4.6.2
+ uuid: 10.0.0
+ zod: 3.24.1
+ zod-to-json-schema: 3.24.1(zod@3.24.1)
+ transitivePeerDependencies:
+ - openai
+
'@leichtgewicht/ip-codec@2.0.4': {}
'@manypkg/find-root@1.1.0':
@@ -18246,6 +18429,8 @@ snapshots:
'@open-draft/until@2.1.0': {}
+ '@opentelemetry/api@1.9.0': {}
+
'@oslojs/encoding@1.1.0': {}
'@parcel/watcher-android-arm64@2.5.1':
@@ -21348,6 +21533,8 @@ snapshots:
dependencies:
'@types/ms': 0.7.34
+ '@types/diff-match-patch@1.0.36': {}
+
'@types/diff@6.0.0': {}
'@types/estree@1.0.5': {}
@@ -21553,6 +21740,8 @@ snapshots:
'@types/unist@3.0.3': {}
+ '@types/uuid@10.0.0': {}
+
'@types/webextension-polyfill@0.10.7': {}
'@types/webpack-env@1.18.8': {}
@@ -22363,6 +22552,18 @@ snapshots:
clean-stack: 4.2.0
indent-string: 5.0.0
+ ai@4.1.34(react@18.3.1)(zod@3.24.1):
+ dependencies:
+ '@ai-sdk/provider': 1.0.7
+ '@ai-sdk/provider-utils': 2.1.6(zod@3.24.1)
+ '@ai-sdk/react': 1.1.11(react@18.3.1)(zod@3.24.1)
+ '@ai-sdk/ui-utils': 1.1.11(zod@3.24.1)
+ '@opentelemetry/api': 1.9.0
+ jsondiffpatch: 0.6.0
+ optionalDependencies:
+ react: 18.3.1
+ zod: 3.24.1
+
ajv-formats@2.1.1(ajv@8.17.1):
optionalDependencies:
ajv: 8.17.1
@@ -22687,7 +22888,7 @@ snapshots:
xxhash-wasm: 1.0.2
yargs-parser: 21.1.1
zod: 3.24.1
- zod-to-json-schema: 3.23.3(zod@3.24.1)
+ zod-to-json-schema: 3.24.1(zod@3.24.1)
zod-to-ts: 1.2.0(typescript@5.6.3)(zod@3.24.1)
optionalDependencies:
sharp: 0.33.5
@@ -23590,6 +23791,10 @@ snapshots:
consola@3.4.0: {}
+ console-table-printer@2.12.1:
+ dependencies:
+ simple-wcswidth: 1.0.1
+
content-disposition@0.5.4:
dependencies:
safe-buffer: 5.2.1
@@ -24212,6 +24417,8 @@ snapshots:
didyoumean@1.2.2: {}
+ diff-match-patch@1.0.5: {}
+
diff-sequences@29.6.3: {}
diff@4.0.2:
@@ -24937,6 +25144,8 @@ snapshots:
events@3.3.0: {}
+ eventsource-parser@3.0.0: {}
+
exec-async@2.2.0: {}
execa@1.0.0:
@@ -27162,6 +27371,10 @@ snapshots:
js-levenshtein@1.1.6: {}
+ js-tiktoken@1.0.18:
+ dependencies:
+ base64-js: 1.5.1
+
js-tokens@4.0.0: {}
js-tokens@9.0.1: {}
@@ -27365,6 +27578,12 @@ snapshots:
json5@2.2.3: {}
+ jsondiffpatch@0.6.0:
+ dependencies:
+ '@types/diff-match-patch': 1.0.36
+ chalk: 5.4.1
+ diff-match-patch: 1.0.5
+
jsonfile@4.0.0:
optionalDependencies:
graceful-fs: 4.2.11
@@ -27441,6 +27660,16 @@ snapshots:
kolorist@1.8.0: {}
+ langsmith@0.3.7:
+ dependencies:
+ '@types/uuid': 10.0.0
+ chalk: 4.1.2
+ console-table-printer: 2.12.1
+ p-queue: 6.6.2
+ p-retry: 4.6.2
+ semver: 7.6.3
+ uuid: 10.0.0
+
language-subtag-registry@0.3.23: {}
language-tags@1.0.9:
@@ -28545,6 +28774,8 @@ snapshots:
dns-packet: 5.6.0
thunky: 1.1.0
+ mustache@4.2.0: {}
+
mute-stream@2.0.0: {}
mv@2.1.1:
@@ -28583,7 +28814,7 @@ snapshots:
nested-error-stacks@2.1.1: {}
- next@14.2.23(@babel/core@7.26.7)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ next@14.2.23(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@next/env': 14.2.23
'@swc/helpers': 0.5.5
@@ -28604,6 +28835,7 @@ snapshots:
'@next/swc-win32-arm64-msvc': 14.2.23
'@next/swc-win32-ia32-msvc': 14.2.23
'@next/swc-win32-x64-msvc': 14.2.23
+ '@opentelemetry/api': 1.9.0
'@playwright/test': 1.44.1
transitivePeerDependencies:
- '@babel/core'
@@ -29279,6 +29511,11 @@ snapshots:
p-map@6.0.0: {}
+ p-queue@6.6.2:
+ dependencies:
+ eventemitter3: 4.0.7
+ p-timeout: 3.2.0
+
p-queue@8.0.1:
dependencies:
eventemitter3: 5.0.1
@@ -29295,6 +29532,10 @@ snapshots:
is-network-error: 1.1.0
retry: 0.13.1
+ p-timeout@3.2.0:
+ dependencies:
+ p-finally: 1.0.0
+
p-timeout@5.1.0: {}
p-timeout@6.1.3: {}
@@ -30976,6 +31217,8 @@ snapshots:
is-arrayish: 0.3.2
optional: true
+ simple-wcswidth@1.0.1: {}
+
sirv@1.0.19:
dependencies:
'@polka/url': 1.0.0-next.28
@@ -31696,6 +31939,8 @@ snapshots:
throttleit@1.0.1: {}
+ throttleit@2.1.0: {}
+
through2@2.0.5:
dependencies:
readable-stream: 2.3.8
@@ -32373,6 +32618,8 @@ snapshots:
utils-merge@1.0.1: {}
+ uuid@10.0.0: {}
+
uuid@7.0.3: {}
uuid@8.3.2: {}
@@ -33322,7 +33569,7 @@ snapshots:
compress-commons: 6.0.2
readable-stream: 4.7.0
- zod-to-json-schema@3.23.3(zod@3.24.1):
+ zod-to-json-schema@3.24.1(zod@3.24.1):
dependencies:
zod: 3.24.1
From b7cdac6931393f6d7bf59cd6888004841f65549c Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 12:53:20 +0200
Subject: [PATCH 03/18] feat(agent-toolkit): Drop CJS
---
packages/agent-toolkit/package.json | 8 +++-----
packages/agent-toolkit/tsconfig.json | 2 +-
packages/agent-toolkit/tsup.config.ts | 4 ++--
scripts/canary.mjs | 1 +
scripts/snapshot.mjs | 1 +
5 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/packages/agent-toolkit/package.json b/packages/agent-toolkit/package.json
index bba03e51a68..ebdb109ee1a 100644
--- a/packages/agent-toolkit/package.json
+++ b/packages/agent-toolkit/package.json
@@ -17,13 +17,11 @@
"sideEffects": false,
"exports": {
"./langchain": {
- "types": "./dist/langchain/index.d.ts",
- "require": "./dist/langchain/index.js",
+ "types": "./dist/langchain/index.d.mts",
"import": "./dist/langchain/index.mjs"
},
"./ai-sdk": {
- "types": "./dist/ai-sdk/index.d.ts",
- "require": "./dist/ai-sdk/index.js",
+ "types": "./dist/ai-sdk/index.d.mts",
"import": "./dist/ai-sdk/index.mjs"
}
},
@@ -35,7 +33,7 @@
"clean": "rimraf ./dist",
"dev": "tsup --watch",
"lint": "eslint src",
- "lint:attw": "attw --pack .",
+ "lint:attw": "attw --pack . --ignore-rules cjs-resolves-to-esm no-resolution",
"lint:publint": "publint",
"test:cache:clear": "jest --clearCache --useStderr"
},
diff --git a/packages/agent-toolkit/tsconfig.json b/packages/agent-toolkit/tsconfig.json
index 57b39d50251..e76dadc1616 100644
--- a/packages/agent-toolkit/tsconfig.json
+++ b/packages/agent-toolkit/tsconfig.json
@@ -7,7 +7,7 @@
"esModuleInterop": true,
"skipLibCheck": true,
"allowJs": true,
- "target": "ES2020",
+ "target": "ES2022",
"emitDeclarationOnly": true,
"declaration": true,
"declarationMap": true,
diff --git a/packages/agent-toolkit/tsup.config.ts b/packages/agent-toolkit/tsup.config.ts
index 7eb4dadc8e0..851d9b5c63c 100644
--- a/packages/agent-toolkit/tsup.config.ts
+++ b/packages/agent-toolkit/tsup.config.ts
@@ -9,10 +9,10 @@ export default defineConfig(overrideOptions => {
entry: ['src/ai-sdk/index.ts', 'src/langchain/index.ts'],
dts: true,
// onSuccess: 'tsc',
- minify: isProd,
+ minify: false,
clean: true,
sourcemap: true,
- format: ['cjs', 'esm'],
+ format: ['esm'],
// legacyOutput: true,
define: {
PACKAGE_NAME: `"${name}"`,
diff --git a/scripts/canary.mjs b/scripts/canary.mjs
index 5c47d167f30..37fb0a3f847 100755
--- a/scripts/canary.mjs
+++ b/scripts/canary.mjs
@@ -10,6 +10,7 @@ const snapshot = `---
'@clerk/clerk-js': patch
'@clerk/backend': patch
'@clerk/fastify': patch
+'@clerk/agent-toolkit': patch
'@clerk/nextjs': patch
'@clerk/shared': patch
'@clerk/themes': patch
diff --git a/scripts/snapshot.mjs b/scripts/snapshot.mjs
index 8b65c77e882..72928b03f41 100755
--- a/scripts/snapshot.mjs
+++ b/scripts/snapshot.mjs
@@ -10,6 +10,7 @@ const snapshot = `---
'@clerk/clerk-js': patch
'@clerk/backend': patch
'@clerk/fastify': patch
+'@clerk/agent-toolkit': patch
'@clerk/nextjs': patch
'@clerk/shared': patch
'@clerk/themes': patch
From bd02552ef6aa2fc26e9ee5cdff016ad5f23f4b29 Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 15:41:23 +0200
Subject: [PATCH 04/18] Update LICENSE
Co-authored-by: Stefanos Anagnostou
---
packages/agent-toolkit/LICENSE | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/agent-toolkit/LICENSE b/packages/agent-toolkit/LICENSE
index 66914b6af7c..49e46cae156 100644
--- a/packages/agent-toolkit/LICENSE
+++ b/packages/agent-toolkit/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2022 Clerk, Inc.
+Copyright (c) 2025 Clerk, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
From e23bd19b8dab9459a6c4fcd1613c33b2d983b8f7 Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 18:19:36 +0200
Subject: [PATCH 05/18] Update .changeset/many-pumpkins-double.md
Co-authored-by: Lennart
---
.changeset/many-pumpkins-double.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.changeset/many-pumpkins-double.md b/.changeset/many-pumpkins-double.md
index 4e4866446f8..76161cc596d 100644
--- a/.changeset/many-pumpkins-double.md
+++ b/.changeset/many-pumpkins-double.md
@@ -6,3 +6,5 @@
Introduce @clerk/agent-toolkit package. The Clerk Agent Toolkit enables popular agent frameworks, including Vercel's AI SDK and LangChain, to integrate with Clerk using tools (also known as function calling).
This package exposes a subset of Clerk's functionality to agent frameworks, allowing you to build powerful agentic systems capable of managing users, user data, organizations, and more.
+
+**Please note:** All relevant information and instructions on how to set it up can be found in the package's README. It's an early developer preview and can't be considered stable yet.
From ca9b72bd170ede012ea540e3b997c311268c00d1 Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 18:19:46 +0200
Subject: [PATCH 06/18] Update .changeset/many-pumpkins-double.md
Co-authored-by: Lennart
---
.changeset/many-pumpkins-double.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.changeset/many-pumpkins-double.md b/.changeset/many-pumpkins-double.md
index 76161cc596d..d1fc8e96969 100644
--- a/.changeset/many-pumpkins-double.md
+++ b/.changeset/many-pumpkins-double.md
@@ -3,7 +3,7 @@
'@clerk/backend': patch
---
-Introduce @clerk/agent-toolkit package. The Clerk Agent Toolkit enables popular agent frameworks, including Vercel's AI SDK and LangChain, to integrate with Clerk using tools (also known as function calling).
+Introduce `@clerk/agent-toolkit` package. The Clerk Agent Toolkit enables popular agent frameworks, including Vercel's AI SDK and LangChain, to integrate with Clerk using tools (also known as function calling).
This package exposes a subset of Clerk's functionality to agent frameworks, allowing you to build powerful agentic systems capable of managing users, user data, organizations, and more.
From fd46df1adfb6c4068c4eb6b6bde5a1d1e4a6e3df Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 18:20:50 +0200
Subject: [PATCH 07/18] Update packages/agent-toolkit/README.md
Co-authored-by: Lennart
---
packages/agent-toolkit/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/agent-toolkit/README.md b/packages/agent-toolkit/README.md
index 8e62a706711..bc956fd1eb9 100644
--- a/packages/agent-toolkit/README.md
+++ b/packages/agent-toolkit/README.md
@@ -25,7 +25,7 @@
-> ℹ️ Developer Preview
+> [!IMPORTANT]
>
> Agent behavior is typically non-deterministic. Ensure you thoroughly test your integration and evaluate your application's performance. Additionally, consider scoping this toolkit's tools to specific users to limit resource access.
>
From 773c4b9459ad05bf558bda6c76b828c472f9a10e Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 18:21:45 +0200
Subject: [PATCH 08/18] Update packages/agent-toolkit/README.md
Co-authored-by: Lennart
---
packages/agent-toolkit/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/agent-toolkit/README.md b/packages/agent-toolkit/README.md
index bc956fd1eb9..5786412c9a4 100644
--- a/packages/agent-toolkit/README.md
+++ b/packages/agent-toolkit/README.md
@@ -58,7 +58,7 @@ The Clerk Agent Toolkit package provides two main import paths:
The toolkit offers the same tools and core APIs across frameworks, but their public interfaces may vary slightly to align with each framework's design:
- `createClerkToolkit(options)`: Instantiates a new Clerk toolkit.
-- `toolkit.injectSessionClaims(systemPrompt)`: Injects session claims (userId, sessionId, orgId, etc.) into the system prompt, making them accessible to the AI model.
+- `toolkit.injectSessionClaims(systemPrompt)`: Injects session claims (`userId`, `sessionId`, `orgId`, etc.) into the system prompt, making them accessible to the AI model.
- `toolkit.users()`: Provides tools for managing users.
- `toolkit.organizations()`: Provides tools for managing organizations.
- `toolkit.allTools()`: Returns all available tools.
From ef2b283ece89159169fe3ed230cf422b88f4dae6 Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 18:22:02 +0200
Subject: [PATCH 09/18] Update packages/agent-toolkit/README.md
Co-authored-by: Lennart
---
packages/agent-toolkit/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/agent-toolkit/README.md b/packages/agent-toolkit/README.md
index 5786412c9a4..93c68c3c268 100644
--- a/packages/agent-toolkit/README.md
+++ b/packages/agent-toolkit/README.md
@@ -64,7 +64,7 @@ The toolkit offers the same tools and core APIs across frameworks, but their pub
- `toolkit.allTools()`: Returns all available tools.
- `toolkit.toolMap()`: **(Langchain only)** Returns an object mapping available tools, useful for calling tools by name.
-For more details on each tool, refer to the framework-specific directories or the [Clerk BAPI documentation](https://clerk.com/docs/reference/backend-api).
+For more details on each tool, refer to the framework-specific directories or the [Clerk Backend API documentation](https://clerk.com/docs/reference/backend-api).
### Prerequisites
From b3e2bf2a4def48bb0ba18dcc9a45e0382b69ee51 Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 18:22:14 +0200
Subject: [PATCH 10/18] Update packages/agent-toolkit/README.md
Co-authored-by: Lennart
---
packages/agent-toolkit/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/agent-toolkit/README.md b/packages/agent-toolkit/README.md
index 93c68c3c268..728345c4646 100644
--- a/packages/agent-toolkit/README.md
+++ b/packages/agent-toolkit/README.md
@@ -69,7 +69,7 @@ For more details on each tool, refer to the framework-specific directories or th
### Prerequisites
- `ai-sdk`: `"^3.4.7 || ^4.0.0"`, or `langchain`: `"^0.3.6"`
-- A Clerk application
+- An existing Clerk application. [Create your account for free](https://dashboard.clerk.com/sign-up?utm_source=github&utm_medium=clerk_agent_toolkit).
- An API key for an AI model compatible with Langchain
### Example Repository
From 81d3728375e36ad91d2c448527a11f3214b06708 Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 18:26:21 +0200
Subject: [PATCH 11/18] Update packages/agent-toolkit/README.md
Co-authored-by: Lennart
---
packages/agent-toolkit/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/agent-toolkit/README.md b/packages/agent-toolkit/README.md
index 728345c4646..eee66e913b4 100644
--- a/packages/agent-toolkit/README.md
+++ b/packages/agent-toolkit/README.md
@@ -190,7 +190,7 @@ export async function POST(req: Request) {
### Using a Custom `clerkClient`
-If you need to set the Clerk secret key dynamically or use different Clerk instances, pass a custom `clerkClient`:
+If you need to set the Clerk secret key dynamically or use different Clerk instances, pass a custom `clerkClient`. Install `@clerk/backend` into your project and call the `createClerkClient` function:
```typescript
import { createClerkToolkit } from '@clerk/agent-toolkit/ai-sdk';
From 48c5cd9dc856ca191883ec4635e1d32154c602fa Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 18:26:38 +0200
Subject: [PATCH 12/18] Update packages/agent-toolkit/README.md
Co-authored-by: Lennart
---
packages/agent-toolkit/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/agent-toolkit/README.md b/packages/agent-toolkit/README.md
index eee66e913b4..4385052cc00 100644
--- a/packages/agent-toolkit/README.md
+++ b/packages/agent-toolkit/README.md
@@ -76,7 +76,7 @@ For more details on each tool, refer to the framework-specific directories or th
- [Clerk AI SDK Example](https://github.com/clerk/agent-toolkit-example)
-## Use with Vercel's AI SDK
+## Using Vercel's AI SDK
1. Install the Clerk Agent Toolkit package:
From b75b0ac8b531f101b7140626f9781ffe25706130 Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 18:48:06 +0200
Subject: [PATCH 13/18] Apply suggestions from code review
Co-authored-by: Lennart
---
packages/agent-toolkit/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/agent-toolkit/README.md b/packages/agent-toolkit/README.md
index 4385052cc00..dc2788ccaf4 100644
--- a/packages/agent-toolkit/README.md
+++ b/packages/agent-toolkit/README.md
@@ -127,7 +127,7 @@ export async function POST(req: Request) {
}
```
-## Use with Langchain
+## Using Langchain
1. Install the Clerk Agent Toolkit package:
From 66508a061313679650b4e4bc7cff5ee5beb7e939 Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 19:29:09 +0200
Subject: [PATCH 14/18] Resolve comments
---
.changeset/many-pumpkins-double.md | 2 +-
.changeset/metal-gorillas-fetch.md | 5 +++++
.github/labeler.yml | 3 +++
packages/agent-toolkit/package.json | 3 +--
packages/agent-toolkit/src/ai-sdk/index.ts | 5 +++++
packages/agent-toolkit/src/langchain/index.ts | 5 +++++
packages/agent-toolkit/src/lib/clerk-client.ts | 13 +++++++------
packages/agent-toolkit/src/lib/types.ts | 17 +++++++++++++++++
8 files changed, 44 insertions(+), 9 deletions(-)
create mode 100644 .changeset/metal-gorillas-fetch.md
diff --git a/.changeset/many-pumpkins-double.md b/.changeset/many-pumpkins-double.md
index d1fc8e96969..e46b7ab49be 100644
--- a/.changeset/many-pumpkins-double.md
+++ b/.changeset/many-pumpkins-double.md
@@ -1,6 +1,5 @@
---
'@clerk/agent-toolkit': patch
-'@clerk/backend': patch
---
Introduce `@clerk/agent-toolkit` package. The Clerk Agent Toolkit enables popular agent frameworks, including Vercel's AI SDK and LangChain, to integrate with Clerk using tools (also known as function calling).
@@ -8,3 +7,4 @@ Introduce `@clerk/agent-toolkit` package. The Clerk Agent Toolkit enables popula
This package exposes a subset of Clerk's functionality to agent frameworks, allowing you to build powerful agentic systems capable of managing users, user data, organizations, and more.
**Please note:** All relevant information and instructions on how to set it up can be found in the package's README. It's an early developer preview and can't be considered stable yet.
+
diff --git a/.changeset/metal-gorillas-fetch.md b/.changeset/metal-gorillas-fetch.md
new file mode 100644
index 00000000000..94396a997e9
--- /dev/null
+++ b/.changeset/metal-gorillas-fetch.md
@@ -0,0 +1,5 @@
+---
+'@clerk/backend': patch
+---
+
+Adds an internal `raw()` getter method to the `User` resource that returns the raw JSON payload of the request that instantiated the resource.
diff --git a/.github/labeler.yml b/.github/labeler.yml
index 0a153507ba3..c60c1ed50e5 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -65,3 +65,6 @@ actions:
integration:
- integration/**
+
+agent-toolkit:
+ - packages/agent-toolkit/**
diff --git a/packages/agent-toolkit/package.json b/packages/agent-toolkit/package.json
index ebdb109ee1a..42e59e36d3e 100644
--- a/packages/agent-toolkit/package.json
+++ b/packages/agent-toolkit/package.json
@@ -34,8 +34,7 @@
"dev": "tsup --watch",
"lint": "eslint src",
"lint:attw": "attw --pack . --ignore-rules cjs-resolves-to-esm no-resolution",
- "lint:publint": "publint",
- "test:cache:clear": "jest --clearCache --useStderr"
+ "lint:publint": "publint"
},
"dependencies": {
"@clerk/backend": "workspace:^",
diff --git a/packages/agent-toolkit/src/ai-sdk/index.ts b/packages/agent-toolkit/src/ai-sdk/index.ts
index 7ad9a86bf1c..8901551349a 100644
--- a/packages/agent-toolkit/src/ai-sdk/index.ts
+++ b/packages/agent-toolkit/src/ai-sdk/index.ts
@@ -20,6 +20,11 @@ export type ClerkToolkit = ClerkToolkitBase & {
[key in keyof typeof tools]: () => { [tool in keyof (typeof tools)[key]]: ReturnType };
};
+/**
+ * Creates a Clerk toolkit with the given parameters.
+ * The toolkit is a collection of tools that can be used to augment the AI's capabilities,
+ * For more details, refer to the [package's docs](https://github.com/clerk/javascript/blob/main/packages/agent-toolkit/README.md).
+ */
export const createClerkToolkit = async (params: CreateClerkToolkitParams = {}): Promise => {
const clerkClient = params.clerkClient || _clerkClient;
const context = params.context || defaultToolkitContext;
diff --git a/packages/agent-toolkit/src/langchain/index.ts b/packages/agent-toolkit/src/langchain/index.ts
index f2c6e0099e1..0882a2e0d3e 100644
--- a/packages/agent-toolkit/src/langchain/index.ts
+++ b/packages/agent-toolkit/src/langchain/index.ts
@@ -25,6 +25,11 @@ export type ClerkToolkit = ClerkToolkitBase & {
[key in keyof typeof tools]: () => Array>;
};
+/**
+ * Creates a Clerk toolkit with the given parameters.
+ * The toolkit is a collection of tools that can be used to augment the AI's capabilities,
+ * For more details, refer to the [package's docs](https://github.com/clerk/javascript/blob/main/packages/agent-toolkit/README.md).
+ */
export const createClerkToolkit = async (params: CreateClerkToolkitParams = {}): Promise => {
const clerkClient = params.clerkClient || _clerkClient;
const context = params.context || defaultToolkitContext;
diff --git a/packages/agent-toolkit/src/lib/clerk-client.ts b/packages/agent-toolkit/src/lib/clerk-client.ts
index 5b709e713ad..4a5cf365380 100644
--- a/packages/agent-toolkit/src/lib/clerk-client.ts
+++ b/packages/agent-toolkit/src/lib/clerk-client.ts
@@ -1,15 +1,16 @@
import { createClerkClient } from '@clerk/backend';
import { apiUrlFromPublishableKey } from '@clerk/shared/apiUrlFromPublishableKey';
+import { getEnvVariable } from '@clerk/shared/getEnvVariable';
-const API_VERSION = process.env.CLERK_API_VERSION || 'v1';
-const SECRET_KEY = process.env.CLERK_SECRET_KEY || '';
-const PUBLISHABLE_KEY = process.env.CLERK_PUBLISHABLE_KEY || '';
-const API_URL = process.env.CLERK_API_URL || apiUrlFromPublishableKey(PUBLISHABLE_KEY);
-const JWT_KEY = process.env.CLERK_JWT_KEY || '';
+const API_VERSION = getEnvVariable('CLERK_API_VERSION') || 'v1';
+const SECRET_KEY = getEnvVariable('CLERK_SECRET_KEY') || '';
+const PUBLISHABLE_KEY = getEnvVariable('CLERK_PUBLISHABLE_KEY') || '';
+const API_URL = getEnvVariable('CLERK_API_URL') || apiUrlFromPublishableKey(PUBLISHABLE_KEY);
+const JWT_KEY = getEnvVariable('CLERK_JWT_KEY') || '';
const SDK_METADATA = {
name: PACKAGE_NAME,
version: PACKAGE_VERSION,
- environment: process.env.NODE_ENV,
+ environment: getEnvVariable('NODE_ENV'),
};
export const clerkClient = createClerkClient({
diff --git a/packages/agent-toolkit/src/lib/types.ts b/packages/agent-toolkit/src/lib/types.ts
index 1c458013db4..75b4a41cb4c 100644
--- a/packages/agent-toolkit/src/lib/types.ts
+++ b/packages/agent-toolkit/src/lib/types.ts
@@ -6,8 +6,25 @@ import type { ClerkTool } from './clerk-tool';
export type SdkAdapter = (clerkClient: ClerkClient, context: ToolkitContext, clerkTool: ClerkTool) => T;
export type ToolkitContext = {
+ /**
+ * The userId of the currently signed-in user.
+ * This is used to scope the tools to a specific user.
+ */
userId?: string;
+ /**
+ * All JWT claims of the current session.
+ * This is used to scope the tools to a specific session or to make the LLM
+ * aware of the sessions details.
+ */
sessionClaims?: SignedInAuthObject['sessionClaims'];
+ /**
+ * Whether to explicitly allow private metadata access.
+ * By default, private metadata are pruned from all resources, before
+ * the resources become available to the LLM. This is important to help avoid
+ * leaking sensitive information to carefully crafted user prompts.
+ *
+ * @default false
+ */
allowPrivateMetadata?: boolean;
};
From 40fa7f10777796ca951c3910e2bd0787dfb16625 Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 19:47:46 +0200
Subject: [PATCH 15/18] Resolve comments
---
pnpm-lock.yaml | 255 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 251 insertions(+), 4 deletions(-)
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 481318c285b..2453b216973 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -302,6 +302,27 @@ importers:
specifier: catalog:repo
version: 8.3.0
+ packages/agent-toolkit:
+ dependencies:
+ '@clerk/backend':
+ specifier: workspace:^
+ version: link:../backend
+ '@clerk/shared':
+ specifier: workspace:^
+ version: link:../shared
+ '@clerk/types':
+ specifier: workspace:^
+ version: link:../types
+ '@langchain/core':
+ specifier: ^0.3.6
+ version: 0.3.39
+ ai:
+ specifier: ^3.4.7 || ^4.0.0
+ version: 4.1.34(react@18.3.1)(zod@3.24.1)
+ zod:
+ specifier: ^3.24.1
+ version: 3.24.1
+
packages/astro:
dependencies:
'@clerk/backend':
@@ -542,7 +563,7 @@ importers:
version: 8.2.2
next:
specifier: ^14.2.23
- version: 14.2.23(@babel/core@7.26.7)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 14.2.23(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
type-fest:
specifier: ^4.33.0
version: 4.33.0
@@ -711,7 +732,7 @@ importers:
version: 4.2.2
next:
specifier: ^14.2.23
- version: 14.2.23(@babel/core@7.26.7)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 14.2.23(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
packages/nuxt:
dependencies:
@@ -1151,6 +1172,40 @@ packages:
'@adobe/css-tools@4.4.0':
resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==}
+ '@ai-sdk/provider-utils@2.1.6':
+ resolution: {integrity: sha512-Pfyaj0QZS22qyVn5Iz7IXcJ8nKIKlu2MeSAdKJzTwkAks7zdLaKVB+396Rqcp1bfQnxl7vaduQVMQiXUrgK8Gw==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ zod: ^3.0.0
+ peerDependenciesMeta:
+ zod:
+ optional: true
+
+ '@ai-sdk/provider@1.0.7':
+ resolution: {integrity: sha512-q1PJEZ0qD9rVR+8JFEd01/QM++csMT5UVwYXSN2u54BrVw/D8TZLTeg2FEfKK00DgAx0UtWd8XOhhwITP9BT5g==}
+ engines: {node: '>=18'}
+
+ '@ai-sdk/react@1.1.11':
+ resolution: {integrity: sha512-vfjZ7w2M+Me83HTMMrnnrmXotz39UDCMd27YQSrvt2f1YCLPloVpLhP+Y9TLZeFE/QiiRCrPYLDQm6aQJYJ9PQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ react: ^18 || ^19 || ^19.0.0-rc
+ zod: ^3.0.0
+ peerDependenciesMeta:
+ react:
+ optional: true
+ zod:
+ optional: true
+
+ '@ai-sdk/ui-utils@1.1.11':
+ resolution: {integrity: sha512-1SC9W4VZLcJtxHRv4Y0aX20EFeaEP6gUvVqoKLBBtMLOgtcZrv/F/HQRjGavGugiwlS3dsVza4X+E78fiwtlTA==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ zod: ^3.0.0
+ peerDependenciesMeta:
+ zod:
+ optional: true
+
'@alcalzone/ansi-tokenize@0.1.3':
resolution: {integrity: sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw==}
engines: {node: '>=14.13.1'}
@@ -1977,6 +2032,9 @@ packages:
'@bundled-es-modules/tough-cookie@0.1.6':
resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==}
+ '@cfworker/json-schema@4.1.1':
+ resolution: {integrity: sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==}
+
'@changesets/apply-release-plan@7.0.5':
resolution: {integrity: sha512-1cWCk+ZshEkSVEZrm2fSj1Gz8sYvxgUL4Q78+1ZZqeqfuevPTPk033/yUZ3df8BKMohkqqHfzj0HOOrG0KtXTw==}
@@ -2811,7 +2869,7 @@ packages:
'@expo/bunyan@4.0.1':
resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==}
- engines: {node: '>=0.10.0'}
+ engines: {'0': node >=0.10.0}
'@expo/cli@0.18.30':
resolution: {integrity: sha512-V90TUJh9Ly8stYo8nwqIqNWCsYjE28GlVFWEhAFCUOp99foiQr8HSTpiiX5GIrprcPoWmlGoY+J5fQA29R4lFg==}
@@ -3290,6 +3348,10 @@ packages:
'@kwsites/promise-deferred@1.1.1':
resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==}
+ '@langchain/core@0.3.39':
+ resolution: {integrity: sha512-muXs4asy1A7qDtcdznxqyBfxf4N6qxofY/S0c95vbsWa0r9YAE2PttHIjcuxSy1q2jUiTkpCcgFEjNJRQRVhEw==}
+ engines: {node: '>=18'}
+
'@leichtgewicht/ip-codec@2.0.4':
resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==}
@@ -3583,6 +3645,10 @@ packages:
'@open-draft/until@2.1.0':
resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
+ '@opentelemetry/api@1.9.0':
+ resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
+ engines: {node: '>=8.0.0'}
+
'@oslojs/encoding@1.1.0':
resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
@@ -5383,6 +5449,9 @@ packages:
'@types/debug@4.1.12':
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
+ '@types/diff-match-patch@1.0.36':
+ resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==}
+
'@types/diff@6.0.0':
resolution: {integrity: sha512-dhVCYGv3ZSbzmQaBSagrv1WJ6rXCdkyTcDyoNu1MD8JohI7pR7k8wdZEm+mvdxRKXyHVwckFzWU1vJc+Z29MlA==}
@@ -5572,6 +5641,9 @@ packages:
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
+ '@types/uuid@10.0.0':
+ resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==}
+
'@types/webextension-polyfill@0.10.7':
resolution: {integrity: sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==}
@@ -6088,6 +6160,18 @@ packages:
resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==}
engines: {node: '>=12'}
+ ai@4.1.34:
+ resolution: {integrity: sha512-9IB5duz6VbXvjibqNrvKz6++PwE8Ui5UfbOC9/CtcQN5Z9sudUQErss+maj7ptoPysD2NPjj99e0Hp183Cz5LQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ react: ^18 || ^19 || ^19.0.0-rc
+ zod: ^3.0.0
+ peerDependenciesMeta:
+ react:
+ optional: true
+ zod:
+ optional: true
+
ajv-formats@2.1.1:
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
@@ -7122,6 +7206,9 @@ packages:
resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==}
engines: {node: ^14.18.0 || >=16.10.0}
+ console-table-printer@2.12.1:
+ resolution: {integrity: sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==}
+
content-disposition@0.5.4:
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
engines: {node: '>= 0.6'}
@@ -7717,6 +7804,9 @@ packages:
didyoumean@1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
+ diff-match-patch@1.0.5:
+ resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==}
+
diff-sequences@29.6.3:
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -8250,6 +8340,10 @@ packages:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
+ eventsource-parser@3.0.0:
+ resolution: {integrity: sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==}
+ engines: {node: '>=18.0.0'}
+
exec-async@2.2.0:
resolution: {integrity: sha512-87OpwcEiMia/DeiKFzaQNBNFeN3XkkpYIh9FyOqq5mS2oKv3CBE67PXoEKcr6nodWdXNogTiQ0jE2NGuoffXPw==}
@@ -9968,6 +10062,9 @@ packages:
resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==}
engines: {node: '>=0.10.0'}
+ js-tiktoken@1.0.18:
+ resolution: {integrity: sha512-hFYx4xYf6URgcttcGvGuOBJhTxPYZ2R5eIesqCaNRJmYH8sNmsfTeWg4yu//7u1VD/qIUkgKJTpGom9oHXmB4g==}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -10096,6 +10193,11 @@ packages:
engines: {node: '>=6'}
hasBin: true
+ jsondiffpatch@0.6.0:
+ resolution: {integrity: sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+
jsonfile@4.0.0:
resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
@@ -10161,6 +10263,14 @@ packages:
kolorist@1.8.0:
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
+ langsmith@0.3.7:
+ resolution: {integrity: sha512-wakN1hxGkm1JR2PpAV7fiT7oC99LKcgxiuUrYGZWPbuj7Y8EPF19F7VNr4B+hA219bfaeWTa4Lxy2YrtPSKnQA==}
+ peerDependencies:
+ openai: '*'
+ peerDependenciesMeta:
+ openai:
+ optional: true
+
language-subtag-registry@0.3.23:
resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==}
@@ -10968,6 +11078,10 @@ packages:
resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==}
hasBin: true
+ mustache@4.2.0:
+ resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
+ hasBin: true
+
mute-stream@2.0.0:
resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==}
engines: {node: ^18.17.0 || >=20.5.0}
@@ -11462,6 +11576,10 @@ packages:
resolution: {integrity: sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==}
engines: {node: '>=16'}
+ p-queue@6.6.2:
+ resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==}
+ engines: {node: '>=8'}
+
p-queue@8.1.0:
resolution: {integrity: sha512-mxLDbbGIBEXTJL0zEx8JIylaj3xQ7Z/7eEVjcF9fJX4DBiH9oqe+oahYnlKKxm0Ci9TlWTyhSHgygxMxjIB2jw==}
engines: {node: '>=18'}
@@ -11474,6 +11592,10 @@ packages:
resolution: {integrity: sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==}
engines: {node: '>=16.17'}
+ p-timeout@3.2.0:
+ resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==}
+ engines: {node: '>=8'}
+
p-timeout@5.1.0:
resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==}
engines: {node: '>=12'}
@@ -12953,6 +13075,9 @@ packages:
simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+ simple-wcswidth@1.0.1:
+ resolution: {integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==}
+
sirv@1.0.19:
resolution: {integrity: sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==}
engines: {node: '>= 10'}
@@ -13572,6 +13697,10 @@ packages:
throttleit@1.0.1:
resolution: {integrity: sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==}
+ throttleit@2.1.0:
+ resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==}
+ engines: {node: '>=18'}
+
through2@2.0.5:
resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==}
@@ -14275,6 +14404,10 @@ packages:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'}
+ uuid@10.0.0:
+ resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
+ hasBin: true
+
uuid@7.0.3:
resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==}
hasBin: true
@@ -15078,6 +15211,37 @@ snapshots:
'@adobe/css-tools@4.4.0': {}
+ '@ai-sdk/provider-utils@2.1.6(zod@3.24.1)':
+ dependencies:
+ '@ai-sdk/provider': 1.0.7
+ eventsource-parser: 3.0.0
+ nanoid: 3.3.8
+ secure-json-parse: 2.7.0
+ optionalDependencies:
+ zod: 3.24.1
+
+ '@ai-sdk/provider@1.0.7':
+ dependencies:
+ json-schema: 0.4.0
+
+ '@ai-sdk/react@1.1.11(react@18.3.1)(zod@3.24.1)':
+ dependencies:
+ '@ai-sdk/provider-utils': 2.1.6(zod@3.24.1)
+ '@ai-sdk/ui-utils': 1.1.11(zod@3.24.1)
+ swr: 2.2.5(react@18.3.1)
+ throttleit: 2.1.0
+ optionalDependencies:
+ react: 18.3.1
+ zod: 3.24.1
+
+ '@ai-sdk/ui-utils@1.1.11(zod@3.24.1)':
+ dependencies:
+ '@ai-sdk/provider': 1.0.7
+ '@ai-sdk/provider-utils': 2.1.6(zod@3.24.1)
+ zod-to-json-schema: 3.24.1(zod@3.24.1)
+ optionalDependencies:
+ zod: 3.24.1
+
'@alcalzone/ansi-tokenize@0.1.3':
dependencies:
ansi-styles: 6.2.1
@@ -16144,6 +16308,8 @@ snapshots:
'@types/tough-cookie': 4.0.5
tough-cookie: 4.1.4
+ '@cfworker/json-schema@4.1.1': {}
+
'@changesets/apply-release-plan@7.0.5':
dependencies:
'@changesets/config': 3.0.3
@@ -17710,6 +17876,23 @@ snapshots:
'@kwsites/promise-deferred@1.1.1': {}
+ '@langchain/core@0.3.39':
+ dependencies:
+ '@cfworker/json-schema': 4.1.1
+ ansi-styles: 5.2.0
+ camelcase: 6.3.0
+ decamelize: 1.2.0
+ js-tiktoken: 1.0.18
+ langsmith: 0.3.7
+ mustache: 4.2.0
+ p-queue: 6.6.2
+ p-retry: 4.6.2
+ uuid: 10.0.0
+ zod: 3.24.1
+ zod-to-json-schema: 3.24.1(zod@3.24.1)
+ transitivePeerDependencies:
+ - openai
+
'@leichtgewicht/ip-codec@2.0.4': {}
'@manypkg/find-root@1.1.0':
@@ -18227,6 +18410,8 @@ snapshots:
'@open-draft/until@2.1.0': {}
+ '@opentelemetry/api@1.9.0': {}
+
'@oslojs/encoding@1.1.0': {}
'@parcel/watcher-android-arm64@2.5.1':
@@ -21325,6 +21510,8 @@ snapshots:
dependencies:
'@types/ms': 0.7.34
+ '@types/diff-match-patch@1.0.36': {}
+
'@types/diff@6.0.0': {}
'@types/estree@1.0.5': {}
@@ -21530,6 +21717,8 @@ snapshots:
'@types/unist@3.0.3': {}
+ '@types/uuid@10.0.0': {}
+
'@types/webextension-polyfill@0.10.7': {}
'@types/webpack-env@1.18.8': {}
@@ -22340,6 +22529,18 @@ snapshots:
clean-stack: 4.2.0
indent-string: 5.0.0
+ ai@4.1.34(react@18.3.1)(zod@3.24.1):
+ dependencies:
+ '@ai-sdk/provider': 1.0.7
+ '@ai-sdk/provider-utils': 2.1.6(zod@3.24.1)
+ '@ai-sdk/react': 1.1.11(react@18.3.1)(zod@3.24.1)
+ '@ai-sdk/ui-utils': 1.1.11(zod@3.24.1)
+ '@opentelemetry/api': 1.9.0
+ jsondiffpatch: 0.6.0
+ optionalDependencies:
+ react: 18.3.1
+ zod: 3.24.1
+
ajv-formats@2.1.1(ajv@8.17.1):
optionalDependencies:
ajv: 8.17.1
@@ -23581,6 +23782,10 @@ snapshots:
consola@3.4.0: {}
+ console-table-printer@2.12.1:
+ dependencies:
+ simple-wcswidth: 1.0.1
+
content-disposition@0.5.4:
dependencies:
safe-buffer: 5.2.1
@@ -24203,6 +24408,8 @@ snapshots:
didyoumean@1.2.2: {}
+ diff-match-patch@1.0.5: {}
+
diff-sequences@29.6.3: {}
diff@4.0.2:
@@ -24930,6 +25137,8 @@ snapshots:
events@3.3.0: {}
+ eventsource-parser@3.0.0: {}
+
exec-async@2.2.0: {}
execa@1.0.0:
@@ -27151,6 +27360,10 @@ snapshots:
js-levenshtein@1.1.6: {}
+ js-tiktoken@1.0.18:
+ dependencies:
+ base64-js: 1.5.1
+
js-tokens@4.0.0: {}
js-tokens@9.0.1: {}
@@ -27354,6 +27567,12 @@ snapshots:
json5@2.2.3: {}
+ jsondiffpatch@0.6.0:
+ dependencies:
+ '@types/diff-match-patch': 1.0.36
+ chalk: 5.4.1
+ diff-match-patch: 1.0.5
+
jsonfile@4.0.0:
optionalDependencies:
graceful-fs: 4.2.11
@@ -27430,6 +27649,16 @@ snapshots:
kolorist@1.8.0: {}
+ langsmith@0.3.7:
+ dependencies:
+ '@types/uuid': 10.0.0
+ chalk: 4.1.2
+ console-table-printer: 2.12.1
+ p-queue: 6.6.2
+ p-retry: 4.6.2
+ semver: 7.7.1
+ uuid: 10.0.0
+
language-subtag-registry@0.3.23: {}
language-tags@1.0.9:
@@ -28527,6 +28756,8 @@ snapshots:
dns-packet: 5.6.0
thunky: 1.1.0
+ mustache@4.2.0: {}
+
mute-stream@2.0.0: {}
mv@2.1.1:
@@ -28565,7 +28796,7 @@ snapshots:
nested-error-stacks@2.1.1: {}
- next@14.2.23(@babel/core@7.26.7)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ next@14.2.23(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.44.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@next/env': 14.2.23
'@swc/helpers': 0.5.5
@@ -28586,6 +28817,7 @@ snapshots:
'@next/swc-win32-arm64-msvc': 14.2.23
'@next/swc-win32-ia32-msvc': 14.2.23
'@next/swc-win32-x64-msvc': 14.2.23
+ '@opentelemetry/api': 1.9.0
'@playwright/test': 1.44.1
transitivePeerDependencies:
- '@babel/core'
@@ -29247,6 +29479,11 @@ snapshots:
p-map@6.0.0: {}
+ p-queue@6.6.2:
+ dependencies:
+ eventemitter3: 4.0.7
+ p-timeout: 3.2.0
+
p-queue@8.1.0:
dependencies:
eventemitter3: 5.0.1
@@ -29263,6 +29500,10 @@ snapshots:
is-network-error: 1.1.0
retry: 0.13.1
+ p-timeout@3.2.0:
+ dependencies:
+ p-finally: 1.0.0
+
p-timeout@5.1.0: {}
p-timeout@6.1.3: {}
@@ -30950,6 +31191,8 @@ snapshots:
is-arrayish: 0.3.2
optional: true
+ simple-wcswidth@1.0.1: {}
+
sirv@1.0.19:
dependencies:
'@polka/url': 1.0.0-next.28
@@ -31670,6 +31913,8 @@ snapshots:
throttleit@1.0.1: {}
+ throttleit@2.1.0: {}
+
through2@2.0.5:
dependencies:
readable-stream: 2.3.8
@@ -32347,6 +32592,8 @@ snapshots:
utils-merge@1.0.1: {}
+ uuid@10.0.0: {}
+
uuid@7.0.3: {}
uuid@8.3.2: {}
From 2bb61db6924f95bd813cce6009645b937fa17e32 Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Tue, 11 Feb 2025 20:04:00 +0200
Subject: [PATCH 16/18] Resolve comments
---
pnpm-lock.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 2453b216973..dde28c6511a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -2869,7 +2869,7 @@ packages:
'@expo/bunyan@4.0.1':
resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==}
- engines: {'0': node >=0.10.0}
+ engines: {node: '>=0.10.0'}
'@expo/cli@0.18.30':
resolution: {integrity: sha512-V90TUJh9Ly8stYo8nwqIqNWCsYjE28GlVFWEhAFCUOp99foiQr8HSTpiiX5GIrprcPoWmlGoY+J5fQA29R4lFg==}
From 3dd4f218d4b685968a22d13605e913011243f504 Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Wed, 12 Feb 2025 13:05:46 +0200
Subject: [PATCH 17/18] Resolve comments
---
packages/agent-toolkit/package.json | 4 ++++
packages/agent-toolkit/tsconfig.json | 4 ++--
packages/agent-toolkit/tsup.config.ts | 2 ++
pnpm-lock.yaml | 4 ++++
4 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/packages/agent-toolkit/package.json b/packages/agent-toolkit/package.json
index 42e59e36d3e..13db0671a88 100644
--- a/packages/agent-toolkit/package.json
+++ b/packages/agent-toolkit/package.json
@@ -15,6 +15,7 @@
"license": "MIT",
"author": "Clerk",
"sideEffects": false,
+ "type": "module",
"exports": {
"./langchain": {
"types": "./dist/langchain/index.d.mts",
@@ -59,5 +60,8 @@
},
"publishConfig": {
"access": "public"
+ },
+ "devDependencies": {
+ "esbuild-plugin-file-path-extensions": "^2.1.4"
}
}
diff --git a/packages/agent-toolkit/tsconfig.json b/packages/agent-toolkit/tsconfig.json
index e76dadc1616..675dd819dd5 100644
--- a/packages/agent-toolkit/tsconfig.json
+++ b/packages/agent-toolkit/tsconfig.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
- "moduleResolution": "NodeNext",
- "module": "NodeNext",
+ "moduleResolution": "Bundler",
+ "module": "ESNext",
"sourceMap": false,
"strict": true,
"esModuleInterop": true,
diff --git a/packages/agent-toolkit/tsup.config.ts b/packages/agent-toolkit/tsup.config.ts
index 851d9b5c63c..d4517b22845 100644
--- a/packages/agent-toolkit/tsup.config.ts
+++ b/packages/agent-toolkit/tsup.config.ts
@@ -1,4 +1,5 @@
import { defineConfig } from 'tsup';
+import { esbuildPluginFilePathExtensions } from 'esbuild-plugin-file-path-extensions';
import { name, version } from './package.json';
@@ -19,5 +20,6 @@ export default defineConfig(overrideOptions => {
PACKAGE_VERSION: `"${version}"`,
__DEV__: `${!isProd}`,
},
+ esbuildPlugins: [esbuildPluginFilePathExtensions({ esmExtension: 'js' })],
};
});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index dde28c6511a..1a50e9f6e78 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -322,6 +322,10 @@ importers:
zod:
specifier: ^3.24.1
version: 3.24.1
+ devDependencies:
+ esbuild-plugin-file-path-extensions:
+ specifier: ^2.1.4
+ version: 2.1.4
packages/astro:
dependencies:
From a9913f2012536d45ead5d9a417d554dc8ed844fd Mon Sep 17 00:00:00 2001
From: Nikos Douvlis
Date: Wed, 12 Feb 2025 13:35:22 +0200
Subject: [PATCH 18/18] chore(repo): Format
---
packages/agent-toolkit/package.json | 14 +++++++-------
packages/agent-toolkit/src/ai-sdk/adapter.ts | 3 +++
packages/agent-toolkit/src/langchain/adapter.ts | 5 ++++-
3 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/packages/agent-toolkit/package.json b/packages/agent-toolkit/package.json
index 13db0671a88..4dbe07f5960 100644
--- a/packages/agent-toolkit/package.json
+++ b/packages/agent-toolkit/package.json
@@ -18,12 +18,12 @@
"type": "module",
"exports": {
"./langchain": {
- "types": "./dist/langchain/index.d.mts",
- "import": "./dist/langchain/index.mjs"
+ "types": "./dist/langchain/index.d.ts",
+ "import": "./dist/langchain/index.js"
},
"./ai-sdk": {
- "types": "./dist/ai-sdk/index.d.mts",
- "import": "./dist/ai-sdk/index.mjs"
+ "types": "./dist/ai-sdk/index.d.ts",
+ "import": "./dist/ai-sdk/index.js"
}
},
"files": [
@@ -43,6 +43,9 @@
"@clerk/types": "workspace:^",
"zod": "^3.24.1"
},
+ "devDependencies": {
+ "esbuild-plugin-file-path-extensions": "^2.1.4"
+ },
"peerDependencies": {
"@langchain/core": "^0.3.6",
"ai": "^3.4.7 || ^4.0.0"
@@ -60,8 +63,5 @@
},
"publishConfig": {
"access": "public"
- },
- "devDependencies": {
- "esbuild-plugin-file-path-extensions": "^2.1.4"
}
}
diff --git a/packages/agent-toolkit/src/ai-sdk/adapter.ts b/packages/agent-toolkit/src/ai-sdk/adapter.ts
index b9ae77033f7..646e35c4e0a 100644
--- a/packages/agent-toolkit/src/ai-sdk/adapter.ts
+++ b/packages/agent-toolkit/src/ai-sdk/adapter.ts
@@ -3,6 +3,9 @@ import { tool } from 'ai';
import type { SdkAdapter } from '../lib/types';
+/**
+ * Converts a `ClerkTool` to an AI SDK `Tool`.
+ */
export const adapter: SdkAdapter = (clerkClient, context, clerkTool) => {
return tool({
description: clerkTool.description,
diff --git a/packages/agent-toolkit/src/langchain/adapter.ts b/packages/agent-toolkit/src/langchain/adapter.ts
index 85bce7461eb..77b5866b795 100644
--- a/packages/agent-toolkit/src/langchain/adapter.ts
+++ b/packages/agent-toolkit/src/langchain/adapter.ts
@@ -3,7 +3,10 @@ import { tool } from '@langchain/core/tools';
import type { SdkAdapter } from '../lib/types';
-// https://js.langchain.com/docs/how_to/custom_tools
+/**
+ * Converts a `ClerkTool` to a LangChain `StructuredTool`.
+ * For more details, take a look at the LangChain docs https://js.langchain.com/docs/how_to/custom_tools
+ */
export const adapter: SdkAdapter = (clerkClient, context, clerkTool) => {
return tool(clerkTool.bindRunnable(clerkClient, context), {
name: clerkTool.name,