Skip to content

Orgs is now a string that can contain orgs per company#10

Merged
joel13samuel merged 3 commits intomainfrom
clerk-org-created
Jul 11, 2025
Merged

Orgs is now a string that can contain orgs per company#10
joel13samuel merged 3 commits intomainfrom
clerk-org-created

Conversation

@joel13samuel
Copy link
Copy Markdown
Contributor

@joel13samuel joel13samuel commented Jul 10, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a new tool to add organizations to a company, allowing multiple organizations to be linked and managed in a single field.
    • Added helper functions for parsing, formatting, and updating organization information within a company’s organization list.
  • Documentation

    • Enhanced documentation to clarify how organizations are handled, including data formats and event workflows.
  • Refactor

    • Updated the format for storing organization information within companies to a string-based format, enabling easier management of multiple organizations.
    • Improved validation and error handling for organization data updates.
  • Bug Fixes

    • Removed unnecessary debug output for cleaner logs.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jul 10, 2025

Walkthrough

This update introduces helper functions for handling organization ID strings, refactors types and schemas to use a string-based format for organization IDs, and adds a new tool, addOrgToCompany, for appending organizations to a company's orgId field. Documentation and workflows are updated to reflect these changes, ensuring consistent handling of organization data.

Changes

File(s) Change Summary
lib/helpers.ts Added helper functions: parseOrgIdString, formatOrgIdString, addOrgToOrgIdString for org ID string manipulation.
lib/attio.ts Removed OrgId type; changed UpdateCompanyObject's orgId from object to string; re-exported new helper functions; updated usages to string format.
src/agents/clerk-agent/tools.ts Added addOrgToCompany tool (metadata, schema, executor); updated updateCompany tool schema to use string for orgId.
src/agents/clerk-agent/index.ts Updated documentation and workflow to describe new orgId string format and use of addOrgToCompany tool.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ClerkAgent
    participant Tools
    participant Helpers

    User->>ClerkAgent: organization.created event
    ClerkAgent->>Tools: getPersonByClerkID
    Tools-->>ClerkAgent: person info
    ClerkAgent->>Tools: getCompanyByPersonEmail
    Tools-->>ClerkAgent: company info
    ClerkAgent->>Tools: addOrgToCompany(companyId, orgName, orgId)
    Tools->>Helpers: addOrgToOrgIdString(existingOrgIdString, orgName, orgId)
    Helpers-->>Tools: new orgId string
    Tools->>Tools: updateCompany(companyId, { orgId: newOrgIdString })
    Tools-->>ClerkAgent: update result
Loading

Poem

🐇
A string of names and IDs, piped and neat,
New helpers hop in—oh, what a treat!
With addOrgToCompany, no duplicates sneak,
Docs are refreshed, the workflows unique.
Now orgs join companies, tidy and bright—
The data is stringy, and all feels right!


📜 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 36ce207 and ca81338.

📒 Files selected for processing (1)
  • src/agents/clerk-agent/tools.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/agents/clerk-agent/tools.ts
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch clerk-org-created

🪧 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 auto-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: 1

🧹 Nitpick comments (2)
lib/helpers.ts (2)

26-33: Enhance input validation and error handling.

The function handles basic edge cases well, but could be more robust with malformed input.

Consider adding validation for malformed entries:

export function parseOrgIdString(orgIdString: string | null | undefined): Array<{name: string, id: string}> {
  if (!orgIdString || typeof orgIdString !== 'string' || orgIdString.trim() === '') return [];
  
  return orgIdString.split('|').map(part => {
    const [name, id] = part.split(':');
    return { name: name?.trim() || '', id: id?.trim() || '' };
-  }).filter(org => org.name && org.id);
+  }).filter(org => org.name && org.id && !org.name.includes(':') && !org.id.includes('|'));
}

41-53: Add input validation and consider return value consistency.

The function works correctly but could benefit from input validation and consistent return values.

Consider these improvements:

export function addOrgToOrgIdString(existingOrgIdString: string | null | undefined, newOrgName: string, newOrgId: string): string {
+ // Validate inputs
+ if (!newOrgName?.trim() || !newOrgId?.trim()) {
+   throw new Error('newOrgName and newOrgId must be non-empty strings');
+ }
+ if (newOrgName.includes(':') || newOrgName.includes('|') || newOrgId.includes(':') || newOrgId.includes('|')) {
+   throw new Error('Organization names and IDs cannot contain ":" or "|" characters');
+ }
+ 
  const existingOrgs = parseOrgIdString(existingOrgIdString);
  
  // Check if org ID already exists
  const existsAlready = existingOrgs.some(org => org.id === newOrgId);
  if (existsAlready) {
-   return existingOrgIdString || ''; // Return empty string if null/undefined
+   return existingOrgIdString || ''; // Consider returning existingOrgIdString as-is
  }
  
  // Add new org
  existingOrgs.push({ name: newOrgName, id: newOrgId });
  return formatOrgIdString(existingOrgs);
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 89476aa and 36ce207.

📒 Files selected for processing (4)
  • lib/attio.ts (5 hunks)
  • lib/helpers.ts (1 hunks)
  • src/agents/clerk-agent/index.ts (3 hunks)
  • src/agents/clerk-agent/tools.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
`src/agents/**/*.ts`: Use TypeScript for better type safety and IDE support Impo...

src/agents/**/*.ts: Use TypeScript for better type safety and IDE support
Import types from '@agentuity/sdk'
Use structured error handling with try/catch blocks
Leverage the provided logger for consistent logging
Use the storage APIs for persisting data

📄 Source: CodeRabbit Inference Engine (.cursor/rules/sdk.mdc)

List of files the instruction was applied to:

  • src/agents/clerk-agent/tools.ts
  • src/agents/clerk-agent/index.ts
`**/src/agents/**/index.ts`: Prefer loading types from the node modules package ...

**/src/agents/**/index.ts: Prefer loading types from the node modules package @agentuity/sdk in the node_modules folder
The file should export a default function
Prefer naming the default function Agent or the name of the Agent based on the context of the Agent description
All code should be in Typescript format
Use the provided logger from the AgentContext interface such as ctx.logger.info("my message: %s", "hello")

📄 Source: CodeRabbit Inference Engine (.cursor/rules/agent.mdc)

List of files the instruction was applied to:

  • src/agents/clerk-agent/index.ts
🧠 Learnings (3)
lib/attio.ts (3)
Learnt from: CR
PR: agentuity/app#0
File: .cursor/rules/monorepo.mdc:0-0
Timestamp: 2025-06-30T15:51:22.047Z
Learning: Applies to **/*.{ts,tsx} : Structure components logically: exports, subcomponents, helpers, types.
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: pec1985
PR: agentuity/app#583
File: lib/data/queries/objectstore.ts:93-93
Timestamp: 2025-06-24T16:59:49.935Z
Learning: In lib/data/queries/objectstore.ts, the provider parameter uses `typeof ObjectStoreProviderEnum` which is a TypeScript enum-like object created from PostgreSQL enum values using `objEnum()`. However, at runtime the actual values are strings, creating a type mismatch that requires casting `as unknown as 'google' | 'aws' | 'azure' | 'agentuity'` to convert between the enum type and string literals.
lib/helpers.ts (1)
Learnt from: CR
PR: agentuity/app#0
File: .cursor/rules/monorepo.mdc:0-0
Timestamp: 2025-06-30T15:51:22.047Z
Learning: Applies to **/*.{ts,tsx} : Structure components logically: exports, subcomponents, helpers, types.
src/agents/clerk-agent/index.ts (13)
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/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/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/agent.mdc:0-0
Timestamp: 2025-06-23T15:29:07.912Z
Learning: When writing an Agent file in TypeScript for Agentuity, always export a default async function that handles the agent logic, typically named Agent or contextually named after the Agent.
Learnt from: CR
PR: agentuity/examples#0
File: agents/agent-riza/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T14:53:38.902Z
Learning: When writing an Agent file in TypeScript for Agentuity, always export a default async function, typically named Agent or contextually named after the Agent.
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/deep-research-js/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T15:28:20.749Z
Learning: Agent files in Agentuity should export a default 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/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/deep-research-js/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T15:28:20.749Z
Learning: Naming the default export function in Agentuity agent files as `Agent` or a contextually relevant name improves clarity and maintainability.
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: agents/Startup_News_Scraper/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-06-23T15:08:01.527Z
Learning: In TypeScript Agent files for Agentuity (located at '**/src/agents/**/index.ts'), always export a default async function that handles the agent logic, typically named 'Agent' or contextually after the agent.
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/agent-crm#0
File: .cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-03T16:12:50.928Z
Learning: Consider agent communication for complex workflows
🔇 Additional comments (11)
lib/attio.ts (3)

3-6: LGTM! Clean helper function imports and re-exports.

The import of helper functions and their re-export for backward compatibility is well-structured and follows good practices.


147-147: LGTM! Correct update to use string format.

The change from updateObject.orgId.id to updateObject.orgId correctly reflects the new string-based format.


38-38: All orgId Usages Have Been Migrated to String Format

  • Searched for any orgId.*\.(id|name) patterns; only comment blocks in src/agents/clerk-agent/index.ts reference .id/.name.
  • No code is still passing an object to UpdateCompanyObject.orgId.

All clear—no further changes needed.

lib/helpers.ts (1)

36-38: LGTM! Clean and efficient implementation.

The formatOrgIdString function is well-implemented and handles the array-to-string conversion correctly.

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

61-69: LGTM! Well-defined tool metadata.

The new tool metadata for addOrgToCompany is properly structured with clear description and parameters.


117-117: LGTM! Correct schema update.

The change from object to optional string for orgId is consistent with the new string-based format.


125-133: LGTM! Proper zod validation schema.

The zod schema for the new tool is well-defined with appropriate parameter types.

src/agents/clerk-agent/index.ts (4)

20-27: LGTM! Clear documentation for new tool and format.

The documentation clearly explains the new addOrgToCompany tool and the organization ID string format, which will help users understand the new workflow.


55-64: LGTM! Updated workflow documentation.

The workflow steps are clearly documented and properly reflect the use of the new addOrgToCompany tool instead of direct company updates.


70-73: LGTM! Clear workflow for organization updates.

The documentation correctly describes how to handle organization updates, including searching by orgId string and updating the organization name within the string.


79-94: LGTM! Enhanced error handling and workflow documentation.

The updated error handling guidance and general workflow steps provide clear direction for using the new organization management approach.

Comment on lines +166 to +187
addOrgToCompany: async ({
companyId,
orgName,
orgId,
}: {
companyId: string;
orgName: string;
orgId: string;
}) => {
// First get the current company to check existing orgId
const company = await attio.getCompanyByRecordID(companyId);
// Extract the actual string value from Attio's attribute structure
const currentOrgId = company?.data?.values?.org_id?.[0]?.value || null;

// Add the new org to the string
const updatedOrgId = attio.addOrgToOrgIdString(currentOrgId, orgName, orgId);

// Update the company with the new orgId string
const result = await attio.updateCompany(companyId, { orgId: updatedOrgId });

return result;
},
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

Enhance error handling and data extraction robustness.

The executor implementation is functional but could be more robust with error handling and data extraction.

Consider these improvements:

addOrgToCompany: async ({
  companyId,
  orgName,
  orgId,
}: {
  companyId: string;
  orgName: string;
  orgId: string;
}) => {
+ try {
    // First get the current company to check existing orgId
    const company = await attio.getCompanyByRecordID(companyId);
+   
+   if (!company?.data) {
+     throw new Error(`Company with ID ${companyId} not found`);
+   }
+   
    // Extract the actual string value from Attio's attribute structure
    const currentOrgId = company?.data?.values?.org_id?.[0]?.value || null;
    
    // Add the new org to the string
    const updatedOrgId = attio.addOrgToOrgIdString(currentOrgId, orgName, orgId);
    
    // Update the company with the new orgId string
    const result = await attio.updateCompany(companyId, { orgId: updatedOrgId });
    
    return result;
+ } catch (error) {
+   throw new Error(`Failed to add org to company: ${error.message}`);
+ }
},
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
addOrgToCompany: async ({
companyId,
orgName,
orgId,
}: {
companyId: string;
orgName: string;
orgId: string;
}) => {
// First get the current company to check existing orgId
const company = await attio.getCompanyByRecordID(companyId);
// Extract the actual string value from Attio's attribute structure
const currentOrgId = company?.data?.values?.org_id?.[0]?.value || null;
// Add the new org to the string
const updatedOrgId = attio.addOrgToOrgIdString(currentOrgId, orgName, orgId);
// Update the company with the new orgId string
const result = await attio.updateCompany(companyId, { orgId: updatedOrgId });
return result;
},
addOrgToCompany: async ({
companyId,
orgName,
orgId,
}: {
companyId: string;
orgName: string;
orgId: string;
}) => {
try {
// First get the current company to check existing orgId
const company = await attio.getCompanyByRecordID(companyId);
if (!company?.data) {
throw new Error(`Company with ID ${companyId} not found`);
}
// Extract the actual string value from Attio's attribute structure
const currentOrgId = company.data.values?.org_id?.[0]?.value || null;
// Add the new org to the string
const updatedOrgId = attio.addOrgToOrgIdString(currentOrgId, orgName, orgId);
// Update the company with the new orgId string
const result = await attio.updateCompany(companyId, { orgId: updatedOrgId });
return result;
} catch (error) {
throw new Error(`Failed to add org to company: ${error.message}`);
}
},
🤖 Prompt for AI Agents
In src/agents/clerk-agent/tools.ts around lines 166 to 187, the addOrgToCompany
function lacks error handling and assumes the data structure is always present.
Improve robustness by adding try-catch blocks to handle potential errors from
async calls and ensure safe extraction of nested data with checks before
accessing properties. Return or log meaningful errors if operations fail to aid
debugging and prevent silent failures.

@joel13samuel joel13samuel merged commit dd068e3 into main Jul 11, 2025
1 check passed
@joel13samuel joel13samuel deleted the clerk-org-created branch July 18, 2025 14:16
This was referenced Jul 28, 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.

2 participants