Orgs is now a string that can contain orgs per company#10
Conversation
WalkthroughThis 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, Changes
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
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
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
📒 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.tssrc/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/sdkin 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 theAgentContextinterface such asctx.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.idtoupdateObject.orgIdcorrectly reflects the new string-based format.
38-38: AllorgIdUsages Have Been Migrated to String Format
- Searched for any
orgId.*\.(id|name)patterns; only comment blocks insrc/agents/clerk-agent/index.tsreference.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
addOrgToCompanyis properly structured with clear description and parameters.
117-117: LGTM! Correct schema update.The change from object to optional string for
orgIdis 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
addOrgToCompanytool 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
addOrgToCompanytool 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.
| 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; | ||
| }, |
There was a problem hiding this comment.
🛠️ 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.
| 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.
Summary by CodeRabbit
New Features
Documentation
Refactor
Bug Fixes