Skip to content

Custom tools + clerk-agent refactor#18

Merged
joel13samuel merged 4 commits intomainfrom
composio-clerk-agent
Jul 21, 2025
Merged

Custom tools + clerk-agent refactor#18
joel13samuel merged 4 commits intomainfrom
composio-clerk-agent

Conversation

@joel13samuel
Copy link
Copy Markdown
Contributor

@joel13samuel joel13samuel commented Jul 18, 2025

Summary by CodeRabbit

  • New Features

    • Added support for executing custom tools alongside existing ones, enhancing workflow flexibility.
    • Introduced structured organization management tools enabling advanced company record operations.
  • Refactor

    • Revised prompts and workflows for clearer, more abstract tool usage.
    • Replaced previous tool implementations with direct API calls to improve reliability and transparency.
  • Bug Fixes

    • Enhanced error handling during tool execution with more explicit error messages.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jul 18, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

The changes extend the agent framework to support execution of custom tools alongside composio tools by updating the createAgent function and its usage. The clerk-agent is refactored to define and use new custom tools for organization management, with executors making direct Attio API calls and structured input schemas.

Changes

File(s) Change Summary
lib/agent.ts Extended createAgent to accept customToolExecutors, separate and execute custom/composio tool calls, and merge results. Function signature updated.
src/agents/clerk-agent/index.ts Revised prompt to use a generic ATTIO toolset with strict iteration and fallback rules; removed tool metadata imports and updated agent creation to exclude executors.
src/agents/clerk-agent/tools.ts Removed old attio-based tool metadata/executors; replaced with commented-out custom tools (Anthropic format) and executors using direct Attio REST API calls for organization management. Helpers for orgId string manipulation referenced.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Agent
    participant Model
    participant CustomTool
    participant ComposioProvider

    Client->>Agent: Send request
    Agent->>Model: Send prompt (with tools)
    Model-->>Agent: Return tool calls
    Agent->>Agent: Separate custom and composio tool calls
    Agent->>CustomTool: Execute custom tool calls (via customToolExecutors)
    CustomTool-->>Agent: Return custom tool results
    Agent->>ComposioProvider: Execute composio tool calls
    ComposioProvider-->>Agent: Return composio tool results
    Agent->>Agent: Merge results
    Agent-->>Client: Return response
Loading

Estimated code review effort

3 (~45 minutes)

Possibly related PRs

Poem

A rabbit hops through agent code,
Now custom tools can share the load!
Clerk’s helpers parse each orgId string,
While Attio APIs do their thing.
With tools and prompts both shiny and new,
The agent’s smarter—thanks to this crew! 🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb10471 and fd426cd.

📒 Files selected for processing (1)
  • lib/agent.ts (5 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch composio-clerk-agent

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/agents/clerk-agent/tools.ts (2)

92-92: Consider defining types for Attio API responses.

Multiple uses of any type reduce type safety. Consider defining interfaces for Attio API responses:

interface AttioCompanyRecord {
  data: {
    values: {
      org_id?: Array<{ value: string | null }>;
      // other fields as needed
    };
  };
  id?: {
    record_id: string;
  };
}

interface AttioQueryResponse {
  data: Array<{
    id?: { record_id: string };
    values: {
      org_id?: Array<{ value: string | null }>;
    };
  }>;
}

Then replace the any types:

-const company = await response.json() as any;
+const company = await response.json() as AttioCompanyRecord;

-const search = await response.json() as any;
+const search = await response.json() as AttioQueryResponse;

Also applies to: 138-138, 143-143, 197-197


123-172: Consider performance implications of fetching all companies.

The getCompaniesByOrgId function fetches all companies and filters in memory, which could be inefficient for large datasets.

Consider:

  1. Checking if Attio API supports server-side filtering for substring searches
  2. Implementing pagination if dealing with many companies
  3. Adding a limit parameter to control the number of results returned
  4. Caching results if this operation is frequent

For now, this approach works but may need optimization as the system scales.

lib/agent.ts (1)

190-266: Well-implemented tool separation and execution logic.

The implementation correctly:

  • Separates custom and composio tool calls
  • Executes custom tools with proper error handling
  • Merges results when both tool types are used

Consider adding type definitions to replace any:

interface ToolCall {
  id: string;
  name: string;
  input: any;
  type: string;
}

interface ToolResult {
  tool_call_id: string;
  type: string;
  content: string;
}

Then update the filter operations:

-const customToolCalls = toolCalls.filter((call: any) => customToolNames.has(call.name));
+const customToolCalls = toolCalls.filter((call: ToolCall) => customToolNames.has(call.name));
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eec6df1 and 88b8d6e.

📒 Files selected for processing (3)
  • lib/agent.ts (5 hunks)
  • src/agents/clerk-agent/index.ts (5 hunks)
  • src/agents/clerk-agent/tools.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/src/agents/**/index.ts

Instructions used from:

Sources:
📄 CodeRabbit Inference Engine

  • .cursor/rules/agent.mdc
src/agents/**/*.ts

Instructions used from:

Sources:
📄 CodeRabbit Inference Engine

  • .cursor/rules/sdk.mdc
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
PR: agentuity/examples#0
File: agents/deep-research-js/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:40:05.817Z
Learning: Applies to agents/deep-research-js/src/agents/**/*.ts : Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/agent-riza/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:31.143Z
Learning: Applies to agents/agent-riza/src/agents/**/*.ts : Consider agent communication (e.g., `response.handoff`, `context.getAgent`) for complex workflows
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-01T12:36:46.237Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/tavily_agent/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:40:30.298Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/agno/from_agno/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:41:16.151Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/composio/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:44.988Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/crewai/basic/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:41:34.015Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/fuse-infra#0
File: .cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-08T16:51:03.227Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/Startup_News_Scraper/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:11.850Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/agent-crm#0
File: .cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-18T15:32:30.780Z
Learning: Consider agent communication for complex workflows
src/agents/clerk-agent/index.ts (21)
Learnt from: CR
PR: agentuity/examples#0
File: agents/deep-research-js/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:40:05.817Z
Learning: Applies to agents/deep-research-js/src/agents/**/*.ts : Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/agent-riza/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:31.143Z
Learning: Applies to agents/agent-riza/src/agents/**/*.ts : Consider agent communication (e.g., `response.handoff`, `context.getAgent`) for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/langgraph/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:14:39.393Z
Learning: In Agentuity AI Agent files (`**/src/agents/**/index.ts`), import types such as `AgentRequest`, `AgentResponse`, and `AgentContext` from the `@agentuity/sdk` package to ensure type safety and consistency.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/mastra/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:15:12.561Z
Learning: In Agentuity AI Agent files (`**/src/agents/**/index.ts`), import types such as `AgentRequest`, `AgentResponse`, and `AgentContext` from the `@agentuity/sdk` package to ensure type safety and consistency.
Learnt from: CR
PR: agentuity/agent-crm#0
File: .cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-18T15:32:21.381Z
Learning: Applies to **/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/fuse-infra#0
File: .cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-08T16:51:03.227Z
Learning: Applies to src/agents/**/*.ts : Import types from '@agentuity/sdk'
Learnt from: CR
PR: agentuity/fuse-infra#0
File: .cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-08T16:50:51.612Z
Learning: Applies to **/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/agent-crm#0
File: .cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-18T15:32:30.780Z
Learning: Applies to src/agents/**/*.ts : Import types from `@agentuity/sdk`
Learnt from: CR
PR: agentuity/examples#0
File: agents/composio/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:44.988Z
Learning: Applies to agents/composio/src/agents/**/*.ts : Import types from `@agentuity/sdk`
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-01T12:36:46.237Z
Learning: Applies to agent-docs/src/agents/**/*.ts : Import types from `@agentuity/sdk`
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/vercel/basic/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-06-23T17:16:58.079Z
Learning: Import types from @agentuity/sdk to ensure consistency and leverage type definitions.
Learnt from: CR
PR: agentuity/examples#0
File: agents/Startup_News_Scraper/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:11.850Z
Learning: Applies to agents/Startup_News_Scraper/src/agents/**/*.ts : Import types from `@agentuity/sdk`
Learnt from: CR
PR: agentuity/examples#0
File: patterns/llmAsJury/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-06-23T17:17:19.027Z
Learning: Import types from @agentuity/sdk to ensure consistency and type safety.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/mastra/basic/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-06-23T17:15:21.314Z
Learning: For best practices in Agentuity SDK projects, use TypeScript for type safety, import types from @agentuity/sdk, use structured error handling with try/catch, leverage the provided logger, use storage APIs for data persistence, and consider agent communication for complex workflows.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/openai/from-oai-typescript/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:15:59.829Z
Learning: In Agent files for Agentuity, always export a default function, preferably named 'Agent' or contextually after the Agent, to ensure consistency and clarity.
Learnt from: CR
PR: agentuity/collider#0
File: projects/collider-node/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-24T15:42:21.297Z
Learning: Agent files for Agentuity should export a default async function, typically named `Agent` or contextually named after the Agent, which receives `AgentRequest`, `AgentResponse`, and `AgentContext` as parameters.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/vercel/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:16:49.315Z
Learning: When writing an Agent in TypeScript for Agentuity, always use the types provided by the `@agentuity/sdk` package for AgentRequest, AgentResponse, and AgentContext to ensure type safety and compatibility.
Learnt from: CR
PR: agentuity/examples#0
File: agentuity/sdk-js/streaming/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:40:37.445Z
Learning: Applies to agentuity/sdk-js/streaming/**/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/examples#0
File: agents/composio/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:39:37.133Z
Learning: Prefer using the `agentuity agent create` command to create a new Agent
Learnt from: CR
PR: agentuity/agent-crm#0
File: .cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-18T15:32:21.381Z
Learning: Prefer using the `agentuity agent create` command to create a new Agent
Learnt from: CR
PR: agentuity/examples#0
File: agentuity/sdk-js/streaming/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:40:37.445Z
Learning: Prefer using the `agentuity agent create` command to create a new Agent
src/agents/clerk-agent/tools.ts (10)
Learnt from: CR
PR: agentuity/examples#0
File: agents/deep-research-js/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:40:05.817Z
Learning: Applies to agents/deep-research-js/src/agents/**/*.ts : Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/langgraph/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:14:39.393Z
Learning: In Agentuity AI Agent files (`**/src/agents/**/index.ts`), import types such as `AgentRequest`, `AgentResponse`, and `AgentContext` from the `@agentuity/sdk` package to ensure type safety and consistency.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/mastra/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:15:12.561Z
Learning: In Agentuity AI Agent files (`**/src/agents/**/index.ts`), import types such as `AgentRequest`, `AgentResponse`, and `AgentContext` from the `@agentuity/sdk` package to ensure type safety and consistency.
Learnt from: CR
PR: agentuity/examples#0
File: agentuity/sdk-js/streaming/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:40:37.445Z
Learning: Applies to agentuity/sdk-js/streaming/**/src/agents/**/index.ts : All code should be in Typescript format
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-01T12:36:46.237Z
Learning: Applies to agent-docs/src/agents/**/*.ts : Use TypeScript for better type safety and IDE support
Learnt from: CR
PR: agentuity/examples#0
File: agents/deep-research-js/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:39:55.775Z
Learning: Applies to agents/deep-research-js/**/src/agents/**/index.ts : All code should be in Typescript format
Learnt from: CR
PR: agentuity/examples#0
File: agents/composio/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:39:37.133Z
Learning: Applies to agents/composio/**/src/agents/**/index.ts : All code should be in Typescript format
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-01T12:36:36.319Z
Learning: Applies to agent-docs/**/src/agents/**/index.ts : All code should be in Typescript format
Learnt from: CR
PR: agentuity/examples#0
File: agentuity/sdk-js/streaming/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:40:50.861Z
Learning: Applies to agentuity/sdk-js/streaming/src/agents/**/*.ts : Use TypeScript for better type safety and IDE support
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/mastra/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:15:12.561Z
Learning: In Agentuity AI Agent files (`**/src/agents/**/index.ts`), always use the provided logger from the `AgentContext` interface (e.g., `ctx.logger.info(...)`) for logging, rather than custom or external logging solutions.
lib/agent.ts (20)
Learnt from: CR
PR: agentuity/examples#0
File: agents/composio/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:39:37.133Z
Learning: Applies to agents/composio/**/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/examples#0
File: agents/deep-research-js/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:40:05.817Z
Learning: Applies to agents/deep-research-js/src/agents/**/*.ts : Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/agent-crm#0
File: .cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-18T15:32:21.381Z
Learning: Applies to **/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/fuse-infra#0
File: .cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-08T16:50:51.612Z
Learning: Applies to **/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/examples#0
File: agents/agent-riza/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:31.143Z
Learning: Applies to agents/agent-riza/src/agents/**/*.ts : Consider agent communication (e.g., `response.handoff`, `context.getAgent`) for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/deep-research-js/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:39:55.775Z
Learning: Applies to agents/deep-research-js/**/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/examples#0
File: agents/composio/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:44.988Z
Learning: Applies to agents/composio/src/agents/**/*.ts : Use TypeScript for better type safety and IDE support
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-01T12:36:36.319Z
Learning: Applies to agent-docs/**/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/mastra/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:15:12.561Z
Learning: In Agentuity AI Agent files (`**/src/agents/**/index.ts`), the default export should be an async function that handles the agent logic, typically accepting parameters `(req: AgentRequest, resp: AgentResponse, ctx: AgentContext)`.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/langgraph/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:14:39.393Z
Learning: In Agentuity AI Agent files (`**/src/agents/**/index.ts`), the default export should be an async function that handles the agent logic, typically accepting parameters `(req: AgentRequest, resp: AgentResponse, ctx: AgentContext)`.
Learnt from: CR
PR: agentuity/collider#0
File: projects/collider-node/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-24T15:42:21.297Z
Learning: Agent files for Agentuity should export a default async function, typically named `Agent` or contextually named after the Agent, which receives `AgentRequest`, `AgentResponse`, and `AgentContext` as parameters.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/vercel/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:16:49.315Z
Learning: When writing an Agent in TypeScript for Agentuity, always use the types provided by the `@agentuity/sdk` package for AgentRequest, AgentResponse, and AgentContext to ensure type safety and compatibility.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/openai/from-oai-typescript/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-06-23T17:16:08.480Z
Learning: In the Agentuity JavaScript SDK, the main handler for an agent should implement the AgentHandler type: (request: AgentRequest, response: AgentResponse, context: AgentContext) => Promise<AgentResponseType>.
Learnt from: CR
PR: agentuity/examples#0
File: patterns/llmAsJury/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-06-23T17:17:19.027Z
Learning: In the Agentuity JavaScript SDK, the main handler for an agent should implement the AgentHandler type: (request: AgentRequest, response: AgentResponse, context: AgentContext) => Promise<AgentResponseType>.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/vercel/basic/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-06-23T17:16:58.079Z
Learning: In the Agentuity JavaScript SDK, the main handler for an agent should implement the AgentHandler type: (request: AgentRequest, response: AgentResponse, context: AgentContext) => Promise<AgentResponseType>.
Learnt from: CR
PR: agentuity/examples#0
File: agentuity/sdk-js/streaming/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:40:37.445Z
Learning: Applies to agentuity/sdk-js/streaming/**/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/examples#0
File: agents/composio/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:39:37.133Z
Learning: Prefer using the `agentuity agent create` command to create a new Agent
Learnt from: CR
PR: agentuity/examples#0
File: agents/agent-riza/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:39:18.709Z
Learning: Prefer using the `agentuity agent create` command to create a new Agent
Learnt from: CR
PR: agentuity/examples#0
File: agentuity/sdk-js/streaming/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:40:37.445Z
Learning: Prefer using the `agentuity agent create` command to create a new Agent
Learnt from: CR
PR: agentuity/agent-crm#0
File: .cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-18T15:32:21.381Z
Learning: Prefer using the `agentuity agent create` command to create a new Agent
🧬 Code Graph Analysis (1)
src/agents/clerk-agent/tools.ts (2)
lib/helpers.ts (3)
  • addOrgToOrgIdString (41-53)
  • parseOrgIdString (26-33)
  • updateOrgNameInOrgIdString (56-76)
lib/attio.ts (3)
  • addOrgToOrgIdString (6-6)
  • parseOrgIdString (6-6)
  • updateOrgNameInOrgIdString (6-6)
🪛 Biome (1.9.4)
src/agents/clerk-agent/tools.ts

[error] 68-68: Don't use 'Function' as a type.

Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.

(lint/complexity/noBannedTypes)


[error] 92-92: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 138-138: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 143-143: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 197-197: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

lib/agent.ts

[error] 9-9: Don't use 'Function' as a type.

Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.

(lint/complexity/noBannedTypes)


[error] 191-191: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 192-192: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 196-196: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 199-200: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 244-244: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)


[error] 244-244: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

🔇 Additional comments (7)
src/agents/clerk-agent/index.ts (3)

2-2: LGTM! Clear and specific naming for custom tools.

The import names clerkExtraTools and clerkToolExecutors clearly indicate these are custom tools specific to the clerk-agent.


14-106: Well-structured prompt with clear tool distinctions.

The updated prompt effectively:

  • Distinguishes between composio ATTIO toolkit and custom organization management tools
  • Provides clear workflow steps for each event type
  • Includes important notes about ATTIO attribute naming conventions

This will help the agent use the appropriate tools for each task.


108-108: Correct integration with the extended createAgent function.

The function call properly passes the custom tools and executors to enable the clerk-agent to use both composio and custom tools.

src/agents/clerk-agent/tools.ts (2)

1-1: LGTM! Appropriate helper imports.

The imported helper functions provide the necessary utilities for manipulating the pipe-delimited organization ID strings.


3-64: Well-defined custom tools with clear schemas.

The tool definitions:

  • Follow the Anthropic format correctly
  • Have descriptive names and clear descriptions
  • Define comprehensive input schemas with required fields
  • Document the pipe-delimited format for organization IDs
lib/agent.ts (2)

47-48: Efficient approach for custom tool identification.

Using a Set for O(1) lookup performance when distinguishing between custom and composio tools.


269-269: Good addition for tracking tool call history.

Accumulating all tool calls across iterations provides valuable context for the agent's decision-making process.

Comment thread src/agents/clerk-agent/tools.ts Outdated
addOrgToCompany: async ({
// Tool executors for the custom tools
// These will be called by composio when the tools are invoked
export const clerkToolExecutors: Record<string, Function> = {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace Function type with explicit type definitions.

Using Function as a type is too permissive and loses type safety benefits.

Define explicit types for the tool executors:

-export const clerkToolExecutors: Record<string, Function> = {
+type ToolExecutor<T = any> = (args: T) => Promise<any>;
+
+export const clerkToolExecutors: Record<string, ToolExecutor> = {

Or even better, create specific types for each tool's arguments:

type AddOrgToCompanyArgs = {
  companyId: string;
  orgName: string;
  orgId: string;
};

type GetCompaniesByOrgIdArgs = {
  orgId: string;
};

type UpdateOrgNameInCompanyArgs = {
  companyId: string;
  orgId: string;
  newOrgName: string;
};

type ClerkToolExecutors = {
  addOrgToCompany: ToolExecutor<AddOrgToCompanyArgs>;
  getCompaniesByOrgId: ToolExecutor<GetCompaniesByOrgIdArgs>;
  updateOrgNameInCompany: ToolExecutor<UpdateOrgNameInCompanyArgs>;
};

export const clerkToolExecutors: ClerkToolExecutors = {
  // ... executors
};
🧰 Tools
🪛 Biome (1.9.4)

[error] 68-68: Don't use 'Function' as a type.

Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.

(lint/complexity/noBannedTypes)

🤖 Prompt for AI Agents
In src/agents/clerk-agent/tools.ts at line 68, replace the use of the generic
Function type for clerkToolExecutors with explicit, well-defined types for each
tool executor's arguments. Define specific argument types for each executor
function, create a ClerkToolExecutors type mapping executor names to their
corresponding ToolExecutor types with these argument types, and then update the
clerkToolExecutors object to use this new ClerkToolExecutors type for improved
type safety and clarity.

Comment thread lib/agent.ts
export const createAgent = (
prompt: string,
extraTools: any[] = [],
customToolExecutors: Record<string, Function> = {},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace Function type with a specific executor type.

The Function type is too permissive and should be replaced with a proper type definition.

+type ToolExecutor = (args: any) => Promise<any>;
+
 export const createAgent = (
   prompt: string, 
   extraTools: any[] = [], 
-  customToolExecutors: Record<string, Function> = {},
+  customToolExecutors: Record<string, ToolExecutor> = {},
🧰 Tools
🪛 Biome (1.9.4)

[error] 9-9: Don't use 'Function' as a type.

Prefer explicitly define the function shape. This type accepts any function-like value, which can be a common source of bugs.

(lint/complexity/noBannedTypes)

🤖 Prompt for AI Agents
In lib/agent.ts at line 9, replace the overly broad `Function` type used in the
`customToolExecutors` record with a more specific executor function type that
accurately describes the expected function signature. Define or import the
appropriate type for the executor functions and use it instead of `Function` to
improve type safety and clarity.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/agents/clerk-agent/index.ts (2)

1-1: Consider importing types from @agentuity/sdk for better type safety.

While the current import is clean, consider importing relevant types from @agentuity/sdk to follow coding guidelines and improve type safety, especially if you plan to add more functionality.

+import type { AgentRequest, AgentResponse, AgentContext } from '@agentuity/sdk';
 import { createAgent } from "../../../lib/agent";

91-91: Consider explicitly naming the default export function.

According to coding guidelines, prefer naming the default function "Agent" or contextually based on the agent description. Consider making this more explicit:

-export default createAgent(clerkWebhookPrompt);
+const ClerkAgent = createAgent(clerkWebhookPrompt);
+export default ClerkAgent;

This improves readability and follows the coding guideline for explicit function naming.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 88b8d6e and cd9be98.

📒 Files selected for processing (1)
  • src/agents/clerk-agent/index.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/src/agents/**/index.ts

Instructions used from:

Sources:
📄 CodeRabbit Inference Engine

  • .cursor/rules/agent.mdc
src/agents/**/*.ts

Instructions used from:

Sources:
📄 CodeRabbit Inference Engine

  • .cursor/rules/sdk.mdc
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
PR: agentuity/examples#0
File: agents/deep-research-js/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:40:05.817Z
Learning: Applies to agents/deep-research-js/src/agents/**/*.ts : Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/agent-riza/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:31.143Z
Learning: Applies to agents/agent-riza/src/agents/**/*.ts : Consider agent communication (e.g., `response.handoff`, `context.getAgent`) for complex workflows
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-01T12:36:46.237Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/tavily_agent/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:40:30.298Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/composio/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:44.988Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/agno/from_agno/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:41:16.151Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/crewai/basic/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:41:34.015Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/fuse-infra#0
File: .cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-08T16:51:03.227Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/agent-crm#0
File: .cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-18T15:32:30.780Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/Startup_News_Scraper/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:11.850Z
Learning: Consider agent communication for complex workflows
src/agents/clerk-agent/index.ts (16)
Learnt from: CR
PR: agentuity/examples#0
File: agents/deep-research-js/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:40:05.817Z
Learning: Applies to agents/deep-research-js/src/agents/**/*.ts : Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/agent-riza/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:31.143Z
Learning: Applies to agents/agent-riza/src/agents/**/*.ts : Consider agent communication (e.g., `response.handoff`, `context.getAgent`) for complex workflows
Learnt from: CR
PR: agentuity/agent-crm#0
File: .cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-18T15:32:21.381Z
Learning: Applies to **/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/fuse-infra#0
File: .cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-08T16:50:51.612Z
Learning: Applies to **/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/examples#0
File: agents/Startup_News_Scraper/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:38:58.657Z
Learning: Applies to agents/Startup_News_Scraper/**/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-01T12:36:36.319Z
Learning: Applies to agent-docs/**/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/mastra/basic/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-06-23T17:15:21.314Z
Learning: For best practices in Agentuity SDK projects, use TypeScript for type safety, import types from @agentuity/sdk, use structured error handling with try/catch, leverage the provided logger, use storage APIs for data persistence, and consider agent communication for complex workflows.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/mastra/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:15:12.561Z
Learning: In Agentuity AI Agent files (`**/src/agents/**/index.ts`), always use the provided logger from the `AgentContext` interface (e.g., `ctx.logger.info(...)`) for logging, rather than custom or external logging solutions.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/langgraph/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:14:39.393Z
Learning: In Agentuity AI Agent files (`**/src/agents/**/index.ts`), always use the provided logger from the `AgentContext` interface (e.g., `ctx.logger.info(...)`) for logging, rather than custom or external logging solutions.
Learnt from: CR
PR: agentuity/examples#0
File: agentuity/sdk-js/streaming/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:40:37.445Z
Learning: Applies to agentuity/sdk-js/streaming/**/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/vercel/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:16:49.315Z
Learning: When writing an Agent in TypeScript for Agentuity, always use the types provided by the `@agentuity/sdk` package for AgentRequest, AgentResponse, and AgentContext to ensure type safety and compatibility.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/openai/from-oai-typescript/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:15:59.829Z
Learning: In Agent files for Agentuity, always export a default function, preferably named 'Agent' or contextually after the Agent, to ensure consistency and clarity.
Learnt from: CR
PR: agentuity/examples#0
File: agents/Startup_News_Scraper/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:38:58.657Z
Learning: Applies to agents/Startup_News_Scraper/**/src/agents/**/index.ts : The file should export a default function
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/vercel/basic/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-06-23T17:16:58.079Z
Learning: Import types from @agentuity/sdk to ensure consistency and leverage type definitions.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/openai/from-oai-typescript/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-06-23T17:16:08.480Z
Learning: Types should be imported from @agentuity/sdk for consistency and type safety.
Learnt from: CR
PR: agentuity/collider#0
File: projects/collider-node/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-24T15:42:21.297Z
Learning: Agent files for Agentuity should export a default async function, typically named `Agent` or contextually named after the Agent, which receives `AgentRequest`, `AgentResponse`, and `AgentContext` as parameters.
🔇 Additional comments (1)
src/agents/clerk-agent/index.ts (1)

1-92: Overall structure follows guidelines well.

The file structure is clean and follows most coding guidelines:

  • ✅ Exports a default function
  • ✅ Uses TypeScript format
  • ✅ Focused and maintainable structure

The refactor successfully simplifies the agent definition by moving complexity to the createAgent function and custom tools, which aligns with the PR objectives.

Comment on lines 3 to 89
const clerkWebhookPrompt = `
You are processing webhooks from Clerk.
Your job is to manage people and companies in Attio based on Clerk user and organization events.

## Webhook Structure
All webhooks contain a \`type\` field that determines the action.
Extract the primary email from \`data.email_addresses[0].email_address\`.
Convert timestamps from Unix milliseconds to ISO strings if needed.

## Available Tools:
- \`getPersonByEmail\` - Find person by email
- \`getPersonByClerkID\` - Find person by Clerk user ID
- \`assertPerson\` - Create/update person (upsert)
- \`getCompanyByPersonEmail\` - Find company associated with person
- \`getCompanyByRecordID\` - Get company by Attio record ID
- \`updateCompany\` - Update company fields
- \`addOrgToCompany\` - Add organization to company's orgId field (handles string concatenation)
- \`getCompaniesByOrgId\` - Find all companies that contain a specific organization ID in their orgId field
- \`updateOrgNameInCompany\` - Update an organization's name in a company's orgId field based on org ID

## Organization ID Format
Companies store multiple organizations in a single \`orgId\` string field using this format:
- Single org: \`"Organization Name:org_id"\`
- Multiple orgs: \`"Org1:id1|Org2:id2|Org3:id3"\`
- Use pipe \`|\` as delimiter between organizations
- Use colon \`:\` to separate name from ID

## Workflow by Event Type:
## ABSOLUTE RULES - NEVER VIOLATE THESE:
1. MAXIMUM 6 iterations total - STOP at 6, no exceptions
2. NEVER make the same tool call twice with identical parameters
3. If a search fails, try ONE alternative pattern, then GIVE UP on that search
4. For organization.created: ONLY update existing companies, NEVER create new ones
5. Track what you've tried - do NOT repeat failed searches

## Available ATTIO Tools:
- \`ATTIO_FIND_RECORD\` - Find records
- \`ATTIO_CREATE_RECORD\` - Create new records
- \`ATTIO_UPDATE_RECORD\` - Update existing records
- \`ATTIO_LIST_RECORDS\` - List records (emergency only)
- \`ATTIO_GET_OBJECT\` - Get schema (emergency only)

## SIMPLE Workflow by Event Type:

### user.created
**Data**: \`data.id\` (Clerk user ID), \`data.created_at\` (Unix timestamp), \`data.email_addresses\`, \`data.first_name\`, \`data.last_name\`

**Steps**:
1. Extract email from \`data.email_addresses[0].email_address\`
2. Convert \`data.created_at\` from Unix milliseconds to ISO string
3. **Check if person already exists**: Use \`getPersonByEmail\` to see if they're already in Attio (e.g., from SmartLead)
4. **Always use \`assertPerson\`** to create/update the person with:
- \`email\`: extracted email
- \`firstName\`: \`data.first_name\`
- \`lastName\`: \`data.last_name\`
- \`userId\`: \`data.id\` (this will add/update the Clerk user ID for existing users)
- \`accountCreationDate\`: converted timestamp
5. **Log the action**: Clearly log whether this was updating an existing person or creating a new one
6. If person has company domain, use \`getCompanyByPersonEmail\` to link them

### user.updated
**Data**: \`data.id\`, \`data.email_addresses\`, \`data.organization_memberships\`

**Steps**:
1. Use \`getPersonByClerkID\` to find existing person
2. If found, extract new email and team info
3. Use \`assertPerson\` to update with new information
4. If team changed, update associated company
**Target: Complete in 3 iterations**
1. **Search person**: \`ATTIO_FIND_RECORD\` with email
2. **Create/update person**: Based on search result
3. **Search/create company**: Based on email domain

### user.updated
**Target: Complete in 2 iterations**
1. **Search person**: \`ATTIO_FIND_RECORD\` by user_id, if fails try email
2. **Update person**: \`ATTIO_UPDATE_RECORD\`

### organization.created
**Data**: \`data.id\` (org ID), \`data.name\` (org name), \`data.created_by\` (user ID who created it)
**Target: Complete in 4 iterations MAXIMUM**

**CRITICAL: This is an ORG CREATED event - the PERSON and COMPANY already exist from user.created. Your job is to FIND them and ADD the org to the company.**

**LINEAR WORKFLOW - Do NOT deviate:**

**Step 1: Find the creator person**
- Try: \`ATTIO_FIND_RECORD\` with \`object_id: "people"\`, \`attributes: { user_id: [{ value: "data.created_by" }] }\`
- If fails: Try \`ATTIO_LIST_RECORDS\` for people (limit 100), manually find person with matching user_id
- If still fails: ABORT - log error and stop

**Step 2: Extract company domain**
- Get creator's email from person record: \`person.values.email_addresses[0].email_address\`
- Extract domain: \`email.split('@')[1]\`

**Step 3: Find the existing company**
- Try: \`ATTIO_FIND_RECORD\` with \`object_id: "companies"\`, \`attributes: { domains: [{ value: "extracted_domain" }] }\`
- If fails: Try \`ATTIO_LIST_RECORDS\` for companies (limit 100), manually find company with matching domain
- If still fails: ABORT - log error, do NOT create company

**Step 4: Update company with org**
- Get current \`org_id\` value from company record
- Parse existing string: \`split('|')\` then \`split(':')\` for each part
- Check if \`data.id\` already exists in parsed orgs
- If not duplicate: append \`"|data.name:data.id"\` to existing string
- Update company: \`ATTIO_UPDATE_RECORD\` with new org_id value

**Steps**:
1. Use \`getPersonByClerkID\` with \`data.created_by\` to find the user who created the organization
2. Use \`getCompanyByPersonEmail\` to find their existing company (Attio auto-creates companies based on email domain)
3. Use \`addOrgToCompany\` with:
- \`companyId\`: company record ID
- \`orgName\`: \`data.name\`
- \`orgId\`: \`data.id\`
4. This will automatically append the new org to the existing orgId string
**CRITICAL RULES:**
- Do NOT repeat failed searches
- Do NOT create new companies
- Do NOT make more than 4 tool calls
- If you can't find creator or company, ABORT with error message

### organization.updated
**Data**: \`data.id\` (org ID), \`data.name\` (org name), \`data.public_metadata.hasOnboarded\`

**Steps**:
1. Use \`getCompaniesByOrgId\` with \`data.id\` to find all companies that have this organization ID in their orgId string
2. For each company found:
- Check if the org name in the orgId string matches \`data.name\`
- If the name is different, use \`updateOrgNameInCompany\` to update the org name in the orgId string
- If \`data.public_metadata.hasOnboarded\` is \`true\`, use \`updateCompany\` to update the \`hasOnboarded\` field to \`true\`
3. Log all actions taken for debugging

## Error Handling:
- If person not found when expected, log warning and continue
- If company operations fail, ensure person operations still complete
- Always log the action taken for debugging
- The \`addOrgToCompany\` tool automatically handles duplicate prevention

## Data Format:
- Store organization IDs as: \`"Organization Name:org_id|Another Org:org_id2"\`
- Convert Unix timestamps (milliseconds) to ISO strings: \`new Date(timestamp).toISOString()\`
- Use ISO timestamps for dates
- Validate email addresses before processing

## General Flow:
1. Always start by identifying the event type from the \`type\` field
2. Extract and validate required data fields
3. Convert Unix timestamps to ISO strings when needed
4. Check if entities exist before creating/updating
5. Use appropriate tools for orgId string manipulation
6. Log all actions taken
7. Handle errors gracefully without stopping the workflow
**Target: Complete in 3 iterations**
1. **Find companies**: \`ATTIO_LIST_RECORDS\` for companies
2. **Filter and parse**: Find companies with matching org_id in string
3. **Update companies**: Modify org data and update records

## Efficiency Rules:
- Count your iterations - stop at limit
- Never repeat identical tool calls
- Use simple string operations for org_id manipulation
- If searches fail after one alternative, give up and log error
- Prioritize completing workflow over perfect data

## Data Extraction:
- Creator ID: \`data.created_by\`
- Org ID: \`data.id\`
- Org Name: \`data.name\`
- Email domain: \`email.split('@')[1]\`
- Parse org string: \`orgString.split('|').map(part => { const [name, id] = part.split(':'); return {name, id}; })\`

**Remember: For organization.created, the person and company ALREADY EXIST. Find them and update the company's org_id field. Do NOT create anything new.**
`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Address potential data structure assumptions and error handling.

The prompt contains several hardcoded assumptions about data structures that could cause runtime errors:

  1. Line 47: person.values.email_addresses[0].email_address assumes the first email address always exists
  2. Line 48: email.split('@')[1] assumes valid email format
  3. Line 57-58: String parsing assumes specific org_id format

Consider adding null checks and validation in the prompt instructions or handling these edge cases gracefully.

-**Step 2: Extract company domain**
-- Get creator's email from person record: \`person.values.email_addresses[0].email_address\`
-- Extract domain: \`email.split('@')[1]\`
+**Step 2: Extract company domain**
+- Get creator's email from person record: \`person.values.email_addresses?.[0]?.email_address\`
+- Validate email exists and has valid format before extracting domain
+- Extract domain: \`email.split('@')[1]\` (only if email contains '@')

Additionally, consider centralizing error handling rules rather than scattering them throughout the workflow sections.

🤖 Prompt for AI Agents
In src/agents/clerk-agent/index.ts around lines 40 to 60, the prompt assumes
person.values.email_addresses[0].email_address always exists and that the email
format is valid for splitting, and also assumes a specific format for parsing
org_id strings. To fix this, update the prompt instructions to include checks
for the existence of email_addresses and validate the email format before
splitting. Similarly, clarify the expected org_id string format and add guidance
to handle unexpected formats gracefully. Additionally, consolidate error
handling instructions into a single section to avoid repetition and improve
clarity.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/agents/clerk-agent/tools.ts (1)

68-68: Function type issue persists in commented code.

The previous review comment about replacing the generic Function type with explicit type definitions is still applicable to this commented code. When this code is re-enabled, the type safety issue will resurface.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd9be98 and eb10471.

📒 Files selected for processing (1)
  • src/agents/clerk-agent/tools.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/agents/**/*.ts

Instructions used from:

Sources:
📄 CodeRabbit Inference Engine

  • .cursor/rules/sdk.mdc
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
PR: agentuity/examples#0
File: agents/deep-research-js/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:40:05.817Z
Learning: Applies to agents/deep-research-js/src/agents/**/*.ts : Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/agent-riza/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:31.143Z
Learning: Applies to agents/agent-riza/src/agents/**/*.ts : Consider agent communication (e.g., `response.handoff`, `context.getAgent`) for complex workflows
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-01T12:36:46.237Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/tavily_agent/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:40:30.298Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/composio/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:44.988Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/agno/from_agno/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:41:16.151Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/crewai/basic/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:41:34.015Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/fuse-infra#0
File: .cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-08T16:51:03.227Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/agent-crm#0
File: .cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-18T15:32:30.780Z
Learning: Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: agents/Startup_News_Scraper/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:11.850Z
Learning: Consider agent communication for complex workflows
src/agents/clerk-agent/tools.ts (23)
Learnt from: CR
PR: agentuity/examples#0
File: agents/deep-research-js/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:40:05.817Z
Learning: Applies to agents/deep-research-js/src/agents/**/*.ts : Consider agent communication for complex workflows
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/langgraph/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:14:39.393Z
Learning: In Agentuity AI Agent files (`**/src/agents/**/index.ts`), import types such as `AgentRequest`, `AgentResponse`, and `AgentContext` from the `@agentuity/sdk` package to ensure type safety and consistency.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/mastra/basic/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:15:12.561Z
Learning: In Agentuity AI Agent files (`**/src/agents/**/index.ts`), import types such as `AgentRequest`, `AgentResponse`, and `AgentContext` from the `@agentuity/sdk` package to ensure type safety and consistency.
Learnt from: CR
PR: agentuity/examples#0
File: agents/composio/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:39:37.133Z
Learning: Applies to agents/composio/**/src/agents/**/index.ts : All code should be in Typescript format
Learnt from: CR
PR: agentuity/examples#0
File: agents/deep-research-js/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:39:55.775Z
Learning: Applies to agents/deep-research-js/**/src/agents/**/index.ts : All code should be in Typescript format
Learnt from: CR
PR: agentuity/examples#0
File: agents/Startup_News_Scraper/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:38:58.657Z
Learning: Applies to agents/Startup_News_Scraper/**/src/agents/**/index.ts : Prefer loading types from the node modules package `@agentuity/sdk` in the node_modules folder
Learnt from: CR
PR: agentuity/examples#0
File: agents/Startup_News_Scraper/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:11.850Z
Learning: Applies to agents/Startup_News_Scraper/src/agents/**/*.ts : Import types from `@agentuity/sdk`
Learnt from: CR
PR: agentuity/examples#0
File: agentuity/sdk-js/streaming/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:40:37.445Z
Learning: Applies to agentuity/sdk-js/streaming/**/src/agents/**/index.ts : All code should be in Typescript format
Learnt from: CR
PR: agentuity/agent-crm#0
File: .cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-18T15:32:21.381Z
Learning: Applies to **/src/agents/**/index.ts : All code should be in Typescript format
Learnt from: CR
PR: agentuity/fuse-infra#0
File: .cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-08T16:50:51.612Z
Learning: Applies to **/src/agents/**/index.ts : All code should be in Typescript format
Learnt from: CR
PR: agentuity/fuse-infra#0
File: .cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-08T16:51:03.227Z
Learning: Applies to src/agents/**/*.ts : Use TypeScript for better type safety and IDE support
Learnt from: CR
PR: agentuity/agent-crm#0
File: .cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-18T15:32:30.780Z
Learning: Applies to src/agents/**/*.ts : Use TypeScript for better type safety and IDE support
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-01T12:36:46.237Z
Learning: Applies to agent-docs/src/agents/**/*.ts : Use TypeScript for better type safety and IDE support
Learnt from: CR
PR: agentuity/examples#0
File: agents/deep-research-js/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:40:05.817Z
Learning: Applies to agents/deep-research-js/src/agents/**/*.ts : Use TypeScript for better type safety and IDE support
Learnt from: CR
PR: agentuity/examples#0
File: agents/composio/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:44.988Z
Learning: Applies to agents/composio/src/agents/**/*.ts : Use TypeScript for better type safety and IDE support
Learnt from: CR
PR: agentuity/examples#0
File: agents/agent-riza/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-17T13:39:31.143Z
Learning: Applies to agents/agent-riza/src/agents/**/*.ts : Use TypeScript for better type safety and IDE support
Learnt from: CR
PR: agentuity/app#0
File: .cursor/rules/monorepo.mdc:0-0
Timestamp: 2025-07-18T15:53:39.814Z
Learning: Applies to **/*.{ts,tsx} : Implement proper type safety and inference.
Learnt from: pec1985
PR: agentuity/app#583
File: lib/data/queries/objectstore.ts:93-93
Timestamp: 2025-06-24T16:59:49.935Z
Learning: The objEnum utility function in lib/data/util.ts creates TypeScript enum-like objects where each key-value pair is identical (e.g., {agentuity: 'agentuity', google: 'google'}). When using typeof ObjectStoreProviderEnum as a parameter type, it expects this enum object type, but runtime code needs the string values, requiring type casting as unknown as string union to bridge this gap.
Learnt from: CR
PR: agentuity/agent-crm#0
File: .cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-18T15:32:21.381Z
Learning: Applies to **/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/fuse-infra#0
File: .cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-08T16:50:51.612Z
Learning: Applies to **/src/agents/**/index.ts : Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/openai/from-oai-typescript/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T17:15:59.829Z
Learning: In Agent files for Agentuity, always export a default function, preferably named 'Agent' or contextually after the Agent, to ensure consistency and clarity.
Learnt from: CR
PR: agentuity/examples#0
File: frameworks/mastra/basic/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-06-23T17:15:21.314Z
Learning: For best practices in Agentuity SDK projects, use TypeScript for type safety, import types from @agentuity/sdk, use structured error handling with try/catch, leverage the provided logger, use storage APIs for data persistence, and consider agent communication for complex workflows.
Learnt from: CR
PR: agentuity/examples#0
File: agents/composio/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-17T13:39:37.133Z
Learning: Applies to agents/composio/**/src/agents/**/index.ts : The file should export a default function
🔇 Additional comments (2)
src/agents/clerk-agent/tools.ts (2)

1-231: Clarify the purpose of commenting out the entire file.

The entire file containing custom tools and executors is commented out, which effectively removes all custom tool functionality for the clerk-agent. This could impact the agent's ability to perform organization management operations as described in the PR objectives.

Please clarify whether this is:

  • Intentional removal of custom tools in favor of composio tools only
  • Temporary commenting during development/testing
  • An incomplete implementation that needs to be re-enabled

5-64: Well-structured tool definitions follow best practices.

The commented Anthropic format tool definitions are well-structured with:

  • Clear descriptions explaining the business logic
  • Proper input schemas with required fields
  • Appropriate type definitions for parameters

This follows the coding guidelines for TypeScript type safety when re-enabled.

Comment on lines +80 to +90
// const response = await fetch(`https://api.attio.com/v2/objects/companies/records/${companyId}`, {
// method: "GET",
// headers: {
// Authorization: `Bearer ${process.env.ATTIO_AUTH_TOKEN}`,
// "Content-Type": "application/json",
// },
// });

// if (!response.ok) {
// throw new Error(`Failed to get company: ${response.status}`);
// }
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add proper error handling and logging for API calls.

The commented executor functions make direct Attio API calls but lack comprehensive error handling and logging. Consider adding:

// Add proper error handling with detailed context
import { logger } from '@agentuity/sdk';

// Example for addOrgToCompany executor:
try {
  const response = await fetch(`https://api.attio.com/v2/objects/companies/records/${companyId}`, {
    method: "GET",
    headers: {
      Authorization: `Bearer ${process.env.ATTIO_AUTH_TOKEN}`,
      "Content-Type": "application/json",
    },
  });
  
  if (!response.ok) {
    const errorText = await response.text();
    logger.error(`Failed to get company ${companyId}: ${response.status} - ${errorText}`);
    throw new Error(`Failed to get company: ${response.status} - ${errorText}`);
  }
  
  const company = await response.json();
  logger.info(`Successfully retrieved company ${companyId}`);
  
  // ... rest of the logic
} catch (error) {
  logger.error(`Error in addOrgToCompany for company ${companyId}:`, error);
  throw error;
}

Also applies to: 101-118, 125-136, 157-169, 185-196, 210-227

🤖 Prompt for AI Agents
In src/agents/clerk-agent/tools.ts between lines 80-90 and also in the ranges
101-118, 125-136, 157-169, 185-196, and 210-227, the commented-out executor
functions making Attio API calls lack proper error handling and logging. To fix
this, wrap the fetch calls in try-catch blocks, use the logger from
'@agentuity/sdk' to log detailed error messages including response status and
error text when the response is not ok, log successful retrievals, and rethrow
errors after logging to ensure proper error propagation and easier debugging.

@joel13samuel joel13samuel merged commit 682e893 into main Jul 21, 2025
1 check was pending
This was referenced Jul 23, 2025
@joel13samuel joel13samuel deleted the composio-clerk-agent branch July 29, 2025 18:32
@coderabbitai coderabbitai Bot mentioned this pull request Jul 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant