Skip to content
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

feat: Update file processor support #1254

Merged
merged 20 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions js/Testing.MD
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The test suite is designed to run across multiple environments. Before running t
- GitHub integration is enabled and active
- Gmail integration is enabled and active
- CodeInterpreter is configured for the default entity
- Github drive and file_id is configured for the default entity

3. Trigger Configuration
- At least one trigger must be active in the system
Expand Down
3 changes: 3 additions & 0 deletions js/config/getTestConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const CURRENT_FILE_DIR = __dirname;
export type BACKEND_CONFIG = {
COMPOSIO_API_KEY: string;
BACKEND_HERMES_URL: string;
drive: {
download_file_id: string;
}
}

export const getTestConfig = (): BACKEND_CONFIG => {
Expand Down
5 changes: 4 additions & 1 deletion js/config/test.config.local.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"COMPOSIO_API_KEY": "",
"BACKEND_HERMES_URL": "http://localhost:9900"
"BACKEND_HERMES_URL": "http://localhost:9900",
"drive":{
"download_file_id":"18rcI9N7cJRG15E2qyWXtNSFeDg4Rj-T3"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded Google Drive file ID in config file poses security risk and reduces flexibility. Should be moved to environment variables or secure configuration management.

📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
"drive":{
"download_file_id":"18rcI9N7cJRG15E2qyWXtNSFeDg4Rj-T3"
}
"drive":{
"download_file_id":"${GOOGLE_DRIVE_FILE_ID}"
}

}
5 changes: 4 additions & 1 deletion js/config/test.config.prod.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"COMPOSIO_API_KEY": "pv7s0lpq7z5vu27cikyls",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API key pv7s0lpq7z5vu27cikyls is hardcoded in the production config file. Sensitive credentials should be loaded from environment variables or a secure key management system.

📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
"COMPOSIO_API_KEY": "pv7s0lpq7z5vu27cikyls",
"COMPOSIO_API_KEY": process.env.COMPOSIO_API_KEY,

"BACKEND_HERMES_URL": "https://backend.composio.dev"
"BACKEND_HERMES_URL": "https://backend.composio.dev",
"drive":{
"download_file_id":"18rcI9N7cJRG15E2qyWXtNSFeDg4Rj-T3"
}
}
5 changes: 4 additions & 1 deletion js/config/test.config.staging.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"COMPOSIO_API_KEY": "gxpf3a5v864651jp741heq",
"BACKEND_HERMES_URL": "https://staging-backend.composio.dev"
"BACKEND_HERMES_URL": "https://staging-backend.composio.dev",
"drive":{
"download_file_id":"18rcI9N7cJRG15E2qyWXtNSFeDg4Rj-T3"
}
}
2 changes: 1 addition & 1 deletion js/openapi-ts.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { defineConfig } from "@hey-api/openapi-ts";

export default defineConfig({
client: "@hey-api/client-axios",
input: "http://localhost:9900/openapi.json",
input: "https://backend.composio.dev/openapi.json",
output: "src/sdk/client",
services: {
asClass: true,
Expand Down
19 changes: 17 additions & 2 deletions js/src/sdk/base.toolset.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,16 +160,17 @@ describe("ComposioToolSet class tests", () => {
const ACTION_NAME = "GMAIL_SEND_EMAIL";
const actions = await toolset.getToolsSchema({ actions: [ACTION_NAME] });

const firstAction = actions[0]!;
// Check if exist
expect(
actions[0]!.parameters.properties["attachment_file_uri_path"]
firstAction.parameters.properties["attachment_schema_parsed_file"]
).toBeDefined();

const requestBody = {
recipient_email: "[email protected]",
subject: "Test email from himanshu",
body: "This is a test email",
attachment_file_uri_path:
attachment_schema_parsed_file:
"https://composio.dev/wp-content/uploads/2024/07/Composio-Logo.webp",
};

Expand All @@ -184,6 +185,20 @@ describe("ComposioToolSet class tests", () => {
expect(executionResult.data).toBeDefined();
});

it("should execute downloadable file action", async () => {
const ACTION_NAME = "GOOGLEDRIVE_PARSE_FILE";
const executionResult = await toolset.executeAction({
action: ACTION_NAME,
params: {
file_id: testConfig.drive.download_file_id,
},
entityId: "default",
});

// @ts-ignore
expect(executionResult.data.file.uri.length).toBeGreaterThan(0);
Comment on lines +198 to +199
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using @ts-ignore to suppress TypeScript errors masks potential runtime issues. Should properly type executionResult.data or handle potential undefined values.

📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
// @ts-ignore
expect(executionResult.data.file.uri.length).toBeGreaterThan(0);
expect(executionResult.data?.file?.uri?.length).toBeGreaterThan(0);

});

it("should get tools with usecase limit", async () => {
const tools = await toolset.getToolsSchema({
useCase: "follow user",
Expand Down
40 changes: 22 additions & 18 deletions js/src/sdk/base.toolset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ import { ActionExecutionResDto } from "./client/types.gen";
import { ActionExecuteResponse, Actions } from "./models/actions";
import { ActiveTriggers } from "./models/activeTriggers";
import { Apps } from "./models/apps";
import { BackendClient } from "./models/backendClient";
import { AxiosBackendClient } from "./models/backendClient";
import { ConnectedAccounts } from "./models/connectedAccounts";
import { Integrations } from "./models/integrations";
import { Triggers } from "./models/triggers";
import { getUserDataJson } from "./utils/config";
import { CEG } from "./utils/error";
import { COMPOSIO_SDK_ERROR_CODES } from "./utils/errors/src/constants";
import {
fileInputProcessor,
fileResponseProcessor,
fileSchemaProcessor,
FILE_DOWNLOADABLE_PROCESSOR,
FILE_INPUT_PROCESSOR,
FILE_SCHEMA_PROCESSOR,
} from "./utils/processor/file";

export type ExecuteActionParams = z.infer<typeof ZExecuteActionParams> & {
Expand All @@ -45,7 +45,7 @@ export class ComposioToolSet {
entityId: string = "default";
connectedAccountIds: Record<string, string> = {};

backendClient: BackendClient;
backendClient: AxiosBackendClient;
connectedAccounts: ConnectedAccounts;
apps: Apps;
actions: Actions;
Expand All @@ -60,9 +60,9 @@ export class ComposioToolSet {
post: TPostProcessor[];
schema: TSchemaProcessor[];
} = {
pre: [fileInputProcessor],
post: [fileResponseProcessor],
schema: [fileSchemaProcessor],
pre: [FILE_INPUT_PROCESSOR],
post: [FILE_DOWNLOADABLE_PROCESSOR],
schema: [FILE_SCHEMA_PROCESSOR],
};

private userDefinedProcessors: {
Expand Down Expand Up @@ -179,17 +179,20 @@ export class ComposioToolSet {
? [this.userDefinedProcessors.schema]
: []),
];

return toolsActions.map((tool) => {
const processedTools = [];
// Iterate over the tools and process them
for (const tool of toolsActions) {
let schema = tool as RawActionData;
allSchemaProcessor.forEach((processor) => {
schema = processor({
// Process the schema with all the processors
for (const processor of allSchemaProcessor) {
schema = await processor({
actionName: schema?.name,
toolSchema: schema,
});
});
return schema;
});
}
processedTools.push(schema);
}
return processedTools;
}

async createAction<P extends Parameters = z.ZodObject<{}>>(
Expand Down Expand Up @@ -245,7 +248,7 @@ export class ComposioToolSet {
];

for (const processor of allInputProcessor) {
params = processor({
params = await processor({
params: params,
actionName: action,
});
Expand Down Expand Up @@ -304,9 +307,10 @@ export class ComposioToolSet {
: []),
];

let dataToReturn = { ...data };
// Dirty way to avoid copy
let dataToReturn = JSON.parse(JSON.stringify(data));
Comment on lines +333 to +334
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep cloning with JSON.parse(JSON.stringify()) can fail for objects with functions, circular references, or special values like undefined. Should use structured cloning or a deep clone library.

📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
// Dirty way to avoid copy
let dataToReturn = JSON.parse(JSON.stringify(data));
// Use structured clone for deep copy
let dataToReturn = structuredClone(data);

for (const processor of allOutputProcessor) {
dataToReturn = processor({
dataToReturn = await processor({
actionName: meta.action,
toolResponse: dataToReturn,
});
Expand Down
128 changes: 126 additions & 2 deletions js/src/sdk/client/schemas.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1492,6 +1492,38 @@ export const $AppQueryDTO = {
type: "object",
} as const;

export const $TestConnector = {
properties: {
id: {
type: "string",
description: "The id of the test connector",
},
name: {
type: "string",
description: "The name of the test connector",
},
authScheme: {
enum: [
"OAUTH2",
"OAUTH1",
"OAUTH1A",
"API_KEY",
"BASIC",
"BEARER_TOKEN",
"GOOGLE_SERVICE_ACCOUNT",
"NO_AUTH",
"BASIC_WITH_JWT",
"COMPOSIO_LINK",
"CALCOM_AUTH",
],
type: "string",
description: "The auth scheme of the test connector",
},
},
type: "object",
required: ["id", "name", "authScheme"],
} as const;

export const $AppInfoResponseDto = {
properties: {
appId: {
Expand Down Expand Up @@ -1534,6 +1566,14 @@ export const $AppInfoResponseDto = {
auth_schemes: {
description: "The authentication schemes of the app",
},
testConnectors: {
items: {
type: "object",
},
type: "array",
$ref: "#/components/schemas/TestConnector",
description: "The authentication schemes of the app",
},
Comment on lines +1569 to +1576
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The testConnectors field in $AppInfoResponseDto has an incorrect type definition - it defines both items and $ref which is invalid OpenAPI schema syntax. Should use only $ref.

📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
testConnectors: {
items: {
type: "object",
},
type: "array",
$ref: "#/components/schemas/TestConnector",
description: "The authentication schemes of the app",
},
testConnectors: {
$ref: "#/components/schemas/TestConnector",
description: "The authentication schemes of the app",
},

enabled: {
type: "boolean",
description: "Indicates if the app is enabled",
Expand Down Expand Up @@ -1746,6 +1786,13 @@ export const $GetConnectorInfoResDTO = {
description:
"When true, indicates that this connector uses Composio's built-in authentication handling rather than custom authentication logic.",
},
limitedActions: {
items: {
type: "string",
},
type: "array",
description: "Array of action strings that this connector is limited to.",
},
},
type: "object",
required: [
Expand All @@ -1756,6 +1803,7 @@ export const $GetConnectorInfoResDTO = {
"logo",
"appName",
"useComposioAuth",
"limitedActions",
],
} as const;

Expand Down Expand Up @@ -1824,6 +1872,14 @@ export const $CreateConnectorPayloadDTO = {
description:
"When set to true, creates a new integration even if one already exists for the given app. This is useful when you need multiple integrations with the same service.",
},
limitedActions: {
items: {
type: "string",
},
type: "array",
description:
"List of actions to limit the connector to. If not provided, all actions will be enabled.",
},
},
type: "object",
required: ["name"],
Expand All @@ -1836,6 +1892,14 @@ export const $PatchConnectorReqDTO = {
description:
"Authentication configuration for the connector. This object contains the necessary credentials and settings required to authenticate with the external service. You can get the required configuration fields from the `GET /api/v1/connectors/{connectorId}/config` endpoint.",
},
limitedActions: {
items: {
type: "string",
},
type: "array",
description:
"A list of actions that are limited or restricted for the connector. This can be used to specify which actions the connector is allowed or not allowed to perform. The list of possible actions can be found in the API documentation.",
},
enabled: {
type: "boolean",
description:
Expand Down Expand Up @@ -4725,6 +4789,66 @@ export const $ActionsQueryV2DTO = {
type: "object",
} as const;

export const $FileInfoDTO = {
properties: {
app: {
type: "string",
description: "Name of the app where this file belongs to.",
},
action: {
type: "string",
description: "Name of the action where this file belongs to.",
},
filename: {
type: "string",
description: "Name of the original file.",
},
mimetype: {
type: "string",
description: "Mime type of the original file.",
},
md5: {
type: "string",
description: "MD5 of a file.",
},
},
type: "object",
required: ["app", "action", "filename", "mimetype", "md5"],
} as const;

export const $GetFilesResponseDTO = {
properties: {
items: {
$ref: "#/components/schemas/FileInfoDTO",
items: {
type: "object",
},
type: "array",
},
},
type: "object",
required: ["items"],
} as const;

export const $CreateUploadURLResponseDTO = {
properties: {
id: {
type: "string",
description: "ID of the file",
},
url: {
type: "string",
description: "Onetime upload URL",
},
key: {
type: "string",
description: "S3 upload location",
},
},
type: "object",
required: ["id", "url", "key"],
} as const;

export const $TimePeriodReqDTO = {
properties: {
lastTimePeriod: {
Expand Down Expand Up @@ -5165,7 +5289,8 @@ export const $ComposioCreateConfigDTO = {
},
useComposioAuth: {
type: "boolean",
description: "Whether to use Composio authentication",
description:
"Whether to use Composio authentication, default to true if no auth config is passed. Throws error we're not able to create integration.",
},
authScheme: {
type: "string",
Expand All @@ -5190,7 +5315,6 @@ export const $ComposioCreateConfigDTO = {
},
},
type: "object",
required: ["authScheme"],
} as const;

export const $ConnectorCreateReqDTO = {
Expand Down
Loading