Skip to content

feat: anthropic-plugin #1465

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions js/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

80 changes: 80 additions & 0 deletions js/src/frameworks/anthropic.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { beforeAll, describe, expect, it } from "@jest/globals";
import { z } from "zod";
import { getTestConfig } from "../../config/getTestConfig";
import { ActionExecuteResponse } from "../sdk/models/actions";
import { AnthropicToolSet } from "./anthropic";
describe("AnthropicToolSet tests", () => {
let anthropicToolset: AnthropicToolSet;
beforeAll(() => {
anthropicToolset = new AnthropicToolSet({
apiKey: getTestConfig().COMPOSIO_API_KEY,
baseUrl: getTestConfig().BACKEND_HERMES_URL,
});
});

it("should get tools as array", async () => {
const tools = await anthropicToolset.getTools({
apps: ["github"],
});

expect(tools).toBeInstanceOf(Array);
});

it("should get specific tool by action name", async () => {
const tools = await anthropicToolset.getTools({
actions: ["GITHUB_GITHUB_API_ROOT"],
});

expect(tools.length).toBe(1);
expect(tools[0]).toHaveProperty("name");
expect(tools[0]).toHaveProperty("description");
expect(tools[0]).toHaveProperty("input_schema");
});

it("should get tools with usecase limit", async () => {
const tools = await anthropicToolset.getTools({
useCase: "follow user",
apps: ["github"],
useCaseLimit: 1,
});

expect(tools.length).toBe(1);
});

it("check if getTools -> actions are coming", async () => {
const tools = await anthropicToolset.getTools({
actions: ["GITHUB_GITHUB_API_ROOT"],
});

expect(Object.keys(tools).length).toBe(1);
});

it("should create and execute custom action", async () => {
await anthropicToolset.createAction({
actionName: "starRepositoryCustomAction",
toolName: "github",
description: "This action stars a repository",
inputParams: z.object({
owner: z.string(),
repo: z.string(),
}),
callback: async (
inputParams,
_authCredentials,
executeRequest
): Promise<ActionExecuteResponse> => {
const res = await executeRequest({
endpoint: `/user/starred/${inputParams.owner}/${inputParams.repo}`,
method: "PUT",
parameters: [],
});
return res;
},
});

const tools = await anthropicToolset.getTools({
actions: ["starRepositoryCustomAction"],
});
expect(tools.length).toBe(1);
});
});
115 changes: 115 additions & 0 deletions js/src/frameworks/anthropic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { Tool } from "@anthropic-ai/sdk/resources/messages/messages.js";
import { z } from "zod";
import { ComposioToolSet as BaseComposioToolSet } from "../sdk/base.toolset";
import { COMPOSIO_BASE_URL } from "../sdk/client/core/OpenAPI";
import { TELEMETRY_LOGGER } from "../sdk/utils/telemetry";
import { TELEMETRY_EVENTS } from "../sdk/utils/telemetry/events";
import { ZToolSchemaFilter } from "../types/base_toolset";
import { Optional } from "../types/util";

export class AnthropicToolSet extends BaseComposioToolSet {
/**
* Composio toolset for Anthropic framework.
*
*/
static FRAMEWORK_NAME = "anthropic";
static DEFAULT_ENTITY_ID = "default";
fileName: string = "js/src/frameworks/anthropic.ts";

constructor(
config: {
apiKey?: Optional<string>;
baseUrl?: Optional<string>;
entityId?: string;
runtime?: string;
} = {}
) {
super({
apiKey: config.apiKey || null,
baseUrl: config.baseUrl || COMPOSIO_BASE_URL,
runtime: config?.runtime || null,
entityId: config.entityId || AnthropicToolSet.DEFAULT_ENTITY_ID,
});
}

private _wrapTool(schema: any, entityId: Optional<string> = null): Tool {
return {
name: schema.name,
description: schema.description,
input_schema: {
type: "object",
properties: schema.parameters.properties || {},
required: schema.parameters.required || [],
},
};
}

async getTools(
filters: z.infer<typeof ZToolSchemaFilter> = {},
entityId: Optional<string> = null
): Promise<Tool[]> {
TELEMETRY_LOGGER.manualTelemetry(TELEMETRY_EVENTS.SDK_METHOD_INVOKED, {
method: "getTools",
file: this.fileName,
params: { filters, entityId },
});

const tools = await this.getToolsSchema(filters, entityId);
return tools.map((tool) => this._wrapTool(tool, entityId || this.entityId));
}

async executeToolCall(
toolCall: { name: string; arguments: string },
entityId: Optional<string> = null
): Promise<string> {
TELEMETRY_LOGGER.manualTelemetry(TELEMETRY_EVENTS.SDK_METHOD_INVOKED, {
method: "executeToolCall",
file: this.fileName,
params: { toolCall, entityId },
});

const toolSchema = await this.getToolsSchema({
actions: [toolCall.name],
});
const appName = toolSchema[0]?.appName?.toLowerCase();
const connectedAccountId = appName && this.connectedAccountIds?.[appName];

return JSON.stringify(
await this.executeAction({
action: toolCall.name,
params: JSON.parse(toolCall.arguments),
entityId: entityId || this.entityId,
connectedAccountId: connectedAccountId,
})
);
}

async handleToolCall(
response: any,
entityId: Optional<string> = null
): Promise<string[]> {
TELEMETRY_LOGGER.manualTelemetry(TELEMETRY_EVENTS.SDK_METHOD_INVOKED, {
method: "handleToolCall",
file: this.fileName,
params: { response, entityId },
});

const outputs: string[] = [];
if (response.content && Array.isArray(response.content)) {
for (const content of response.content) {
if (content.type === "tool_use") {
outputs.push(
await this.executeToolCall(
{
name: content.name,
arguments: JSON.stringify(content.input),
},
entityId
)
);
}
}
}
return outputs;
}
}
2 changes: 2 additions & 0 deletions js/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AnthropicToolSet } from "./frameworks/anthropic";
import { CloudflareToolSet } from "./frameworks/cloudflare";
import { LangchainToolSet } from "./frameworks/langchain";
import { LangGraphToolSet } from "./frameworks/langgraph";
Expand All @@ -15,6 +16,7 @@ export {
// Constants
ACTIONS,
APPS,
AnthropicToolSet,
COMPOSIO_SDK_ERROR_CODES,
// Frameworks
CloudflareToolSet,
Expand Down
Loading