diff --git a/apps/docs/content/docs/en/tools/agiloft.mdx b/apps/docs/content/docs/en/tools/agiloft.mdx index 235300ea259..5032b74663d 100644 --- a/apps/docs/content/docs/en/tools/agiloft.mdx +++ b/apps/docs/content/docs/en/tools/agiloft.mdx @@ -7,7 +7,7 @@ import { BlockInfoCard } from "@/components/ui/block-info-card" {/* MANUAL-CONTENT-START:intro */} @@ -137,6 +137,28 @@ Delete a record from an Agiloft table. | `id` | string | ID of the deleted record | | `deleted` | boolean | Whether the record was successfully deleted | +### `agiloft_get_choice_line_id` + +Resolve the internal numeric ID of a choice-list value, for use in EWSelect WHERE clauses against choice fields. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `instanceUrl` | string | Yes | Agiloft instance URL \(e.g., https://mycompany.agiloft.com\) | +| `knowledgeBase` | string | Yes | Knowledge base name | +| `login` | string | Yes | Agiloft username | +| `password` | string | Yes | Agiloft password | +| `table` | string | Yes | Table name \(e.g., "case", "contracts"\) | +| `fieldName` | string | Yes | Choice field name \(e.g., "priority", "status"\) | +| `value` | string | Yes | Choice display value to resolve \(e.g., "High", "Active"\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `choiceLineId` | number | Internal numeric line ID of the choice value | + ### `agiloft_lock_record` Lock, unlock, or check the lock status of an Agiloft record. @@ -254,7 +276,7 @@ List saved searches defined for an Agiloft table. | `searches` | array | List of saved searches for the table | | ↳ `name` | string | Saved search name | | ↳ `label` | string | Saved search display label | -| ↳ `id` | string | Saved search database identifier | +| ↳ `id` | number | Saved search database identifier | | ↳ `description` | string | Saved search description | ### `agiloft_search_records` diff --git a/apps/docs/content/docs/en/tools/posthog.mdx b/apps/docs/content/docs/en/tools/posthog.mdx index 61b50e82810..6b471ef60fb 100644 --- a/apps/docs/content/docs/en/tools/posthog.mdx +++ b/apps/docs/content/docs/en/tools/posthog.mdx @@ -87,7 +87,7 @@ List persons (users) in PostHog. Returns user profiles with their properties and | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `personalApiKey` | string | Yes | PostHog Personal API Key \(for authenticated API access\) | +| `apiKey` | string | Yes | PostHog Personal API Key \(for authenticated API access\) | | `region` | string | No | PostHog region: us \(default\) or eu | | `projectId` | string | Yes | PostHog Project ID \(e.g., "12345" or project UUID\) | | `limit` | number | No | Number of persons to return \(default: 100, max: 100\) | @@ -115,7 +115,7 @@ Get detailed information about a specific person in PostHog by their ID or UUID. | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `personalApiKey` | string | Yes | PostHog Personal API Key \(for authenticated API access\) | +| `apiKey` | string | Yes | PostHog Personal API Key \(for authenticated API access\) | | `region` | string | No | PostHog region: us \(default\) or eu | | `projectId` | string | Yes | PostHog Project ID \(e.g., "12345" or project UUID\) | | `personId` | string | Yes | Person ID or UUID to retrieve \(e.g., "01234567-89ab-cdef-0123-456789abcdef"\) | @@ -139,7 +139,7 @@ Delete a person from PostHog. This will remove all associated events and data. U | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `personalApiKey` | string | Yes | PostHog Personal API Key \(for authenticated API access\) | +| `apiKey` | string | Yes | PostHog Personal API Key \(for authenticated API access\) | | `region` | string | No | PostHog region: us \(default\) or eu | | `projectId` | string | Yes | PostHog Project ID \(e.g., "12345" or project UUID\) | | `personId` | string | Yes | Person ID or UUID to delete \(e.g., "01234567-89ab-cdef-0123-456789abcdef"\) | @@ -158,7 +158,7 @@ Execute a HogQL query in PostHog. HogQL is PostHog | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `personalApiKey` | string | Yes | PostHog Personal API Key \(for authenticated API access\) | +| `apiKey` | string | Yes | PostHog Personal API Key \(for authenticated API access\) | | `region` | string | No | PostHog region: us \(default\) or eu | | `projectId` | string | Yes | PostHog Project ID \(e.g., "12345" or project UUID\) | | `query` | string | Yes | HogQL query to execute. Example: \{"kind": "HogQLQuery", "query": "SELECT event, count\(\) FROM events WHERE timestamp > now\(\) - INTERVAL 1 DAY GROUP BY event"\} | diff --git a/apps/sim/app/(landing)/integrations/data/integrations.json b/apps/sim/app/(landing)/integrations/data/integrations.json index 346cb98feeb..7067930cb24 100644 --- a/apps/sim/app/(landing)/integrations/data/integrations.json +++ b/apps/sim/app/(landing)/integrations/data/integrations.json @@ -321,7 +321,7 @@ "name": "Agiloft", "description": "Manage records in Agiloft CLM", "longDescription": "Integrate with Agiloft contract lifecycle management to create, read, update, delete, and search records. Supports file attachments, SQL-based selection, saved searches, and record locking across any table in your knowledge base.", - "bgColor": "#FFFFFF", + "bgColor": "#001028", "iconName": "AgiloftIcon", "docsUrl": "https://docs.sim.ai/tools/agiloft", "operations": [ @@ -372,9 +372,13 @@ { "name": "Lock Record", "description": "Lock, unlock, or check the lock status of an Agiloft record." + }, + { + "name": "Get Choice Line ID", + "description": "Resolve the internal numeric ID of a choice-list value, for use in EWSelect WHERE clauses against choice fields." } ], - "operationCount": 12, + "operationCount": 13, "triggers": [], "triggerCount": 0, "authType": "none", diff --git a/apps/sim/app/api/tools/agiloft/attach/route.ts b/apps/sim/app/api/tools/agiloft/attach/route.ts index d0ec62e0fd8..edcbdc4c0f3 100644 --- a/apps/sim/app/api/tools/agiloft/attach/route.ts +++ b/apps/sim/app/api/tools/agiloft/attach/route.ts @@ -1,4 +1,5 @@ import { createLogger } from '@sim/logger' +import { toError } from '@sim/utils/errors' import { type NextRequest, NextResponse } from 'next/server' import { agiloftAttachContract } from '@/lib/api/contracts/tools/agiloft' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' @@ -90,7 +91,7 @@ export const POST = withRouteHandler(async (request: NextRequest) => { const agiloftResponse = await fetch(url, { method: 'PUT', headers: { - 'Content-Type': userFile.type || 'application/octet-stream', + 'Content-Type': 'application/octet-stream', Authorization: `Bearer ${token}`, }, body: new Uint8Array(fileBuffer), @@ -136,9 +137,6 @@ export const POST = withRouteHandler(async (request: NextRequest) => { } catch (error) { logger.error(`[${requestId}] Error attaching file to Agiloft:`, error) - return NextResponse.json( - { success: false, error: error instanceof Error ? error.message : 'Internal server error' }, - { status: 500 } - ) + return NextResponse.json({ success: false, error: toError(error).message }, { status: 500 }) } }) diff --git a/apps/sim/app/api/tools/agiloft/retrieve/route.ts b/apps/sim/app/api/tools/agiloft/retrieve/route.ts index 3f94c8bc739..64bd72daae8 100644 --- a/apps/sim/app/api/tools/agiloft/retrieve/route.ts +++ b/apps/sim/app/api/tools/agiloft/retrieve/route.ts @@ -1,4 +1,5 @@ import { createLogger } from '@sim/logger' +import { toError } from '@sim/utils/errors' import { type NextRequest, NextResponse } from 'next/server' import { agiloftRetrieveContract } from '@/lib/api/contracts/tools/agiloft' import { getValidationErrorMessage, parseRequest } from '@/lib/api/server' @@ -127,9 +128,6 @@ export const POST = withRouteHandler(async (request: NextRequest) => { } catch (error) { logger.error(`[${requestId}] Error retrieving Agiloft attachment:`, error) - return NextResponse.json( - { success: false, error: error instanceof Error ? error.message : 'Internal server error' }, - { status: 500 } - ) + return NextResponse.json({ success: false, error: toError(error).message }, { status: 500 }) } }) diff --git a/apps/sim/blocks/blocks/agiloft.ts b/apps/sim/blocks/blocks/agiloft.ts index 36e571dad99..ee1791d3048 100644 --- a/apps/sim/blocks/blocks/agiloft.ts +++ b/apps/sim/blocks/blocks/agiloft.ts @@ -13,7 +13,7 @@ export const AgiloftBlock: BlockConfig = { category: 'tools', integrationType: IntegrationType.Productivity, tags: ['automation'], - bgColor: '#FFFFFF', + bgColor: '#001028', icon: AgiloftIcon, authMode: AuthMode.ApiKey, @@ -35,6 +35,7 @@ export const AgiloftBlock: BlockConfig = { { label: 'Remove Attachment', id: 'remove_attachment' }, { label: 'Attachment Info', id: 'attachment_info' }, { label: 'Lock Record', id: 'lock_record' }, + { label: 'Get Choice Line ID', id: 'get_choice_line_id' }, ], value: () => 'search_records', }, @@ -44,7 +45,6 @@ export const AgiloftBlock: BlockConfig = { type: 'short-input', placeholder: 'https://mycompany.agiloft.com', required: true, - password: false, }, { id: 'knowledgeBase', @@ -151,16 +151,36 @@ export const AgiloftBlock: BlockConfig = { id: 'fieldName', title: 'Field Name', type: 'short-input', - placeholder: 'e.g., attached_docs', + placeholder: 'e.g., attached_docs, priority', condition: { field: 'operation', - value: ['attach_file', 'retrieve_attachment', 'remove_attachment', 'attachment_info'], + value: [ + 'attach_file', + 'retrieve_attachment', + 'remove_attachment', + 'attachment_info', + 'get_choice_line_id', + ], }, required: { field: 'operation', - value: ['attach_file', 'retrieve_attachment', 'remove_attachment', 'attachment_info'], + value: [ + 'attach_file', + 'retrieve_attachment', + 'remove_attachment', + 'attachment_info', + 'get_choice_line_id', + ], }, }, + { + id: 'value', + title: 'Choice Value', + type: 'short-input', + placeholder: 'e.g., High, Active', + condition: { field: 'operation', value: 'get_choice_line_id' }, + required: { field: 'operation', value: 'get_choice_line_id' }, + }, { id: 'uploadFile', title: 'File', @@ -254,6 +274,7 @@ export const AgiloftBlock: BlockConfig = { 'agiloft_attachment_info', 'agiloft_create_record', 'agiloft_delete_record', + 'agiloft_get_choice_line_id', 'agiloft_lock_record', 'agiloft_read_record', 'agiloft_remove_attachment', @@ -288,7 +309,8 @@ export const AgiloftBlock: BlockConfig = { data: { type: 'string', description: 'Record data as JSON' }, query: { type: 'string', description: 'Search query' }, where: { type: 'string', description: 'SQL WHERE clause for select' }, - fieldName: { type: 'string', description: 'Attachment field name' }, + fieldName: { type: 'string', description: 'Attachment field name or choice field name' }, + value: { type: 'string', description: 'Choice value to resolve to its line ID' }, attachFile: { type: 'file', description: 'File to attach' }, fileName: { type: 'string', description: 'Name for the attached file' }, position: { type: 'string', description: 'Attachment position index' }, @@ -403,5 +425,10 @@ export const AgiloftBlock: BlockConfig = { description: 'Minutes until the lock expires', condition: { field: 'operation', value: 'lock_record' }, }, + choiceLineId: { + type: 'number', + description: 'Internal numeric ID of the resolved choice value', + condition: { field: 'operation', value: 'get_choice_line_id' }, + }, }, } diff --git a/apps/sim/lib/api/contracts/tools/agiloft.ts b/apps/sim/lib/api/contracts/tools/agiloft.ts index 38b18657eb9..f8c6e1f565c 100644 --- a/apps/sim/lib/api/contracts/tools/agiloft.ts +++ b/apps/sim/lib/api/contracts/tools/agiloft.ts @@ -50,8 +50,8 @@ export const agiloftAttachBodySchema = z.object({ table: z.string().min(1, 'Table is required'), recordId: z.string().min(1, 'Record ID is required'), fieldName: z.string().min(1, 'Field name is required'), - file: FileInputSchema.optional().nullable(), - fileName: z.string().optional().nullable(), + file: FileInputSchema.optional(), + fileName: z.string().optional(), }) export const agiloftRetrieveContract = defineRouteContract({ diff --git a/apps/sim/tools/agiloft/attachment_info.ts b/apps/sim/tools/agiloft/attachment_info.ts index 38471b74e3b..07986303fe8 100644 --- a/apps/sim/tools/agiloft/attachment_info.ts +++ b/apps/sim/tools/agiloft/attachment_info.ts @@ -91,9 +91,13 @@ export const agiloftAttachmentInfoTool: ToolConfig< for (let i = 0; i < result.length; i++) { const item = result[i] as Record attachments.push({ - position: (item.position as number) ?? i, - name: (item.name as string) ?? (item.filename as string) ?? '', - size: (item.size as number) ?? 0, + position: (item.filePosition as number) ?? (item.position as number) ?? i, + name: + (item.fileName as string) ?? + (item.name as string) ?? + (item.filename as string) ?? + '', + size: (item.size as number) ?? (item.fileSize as number) ?? 0, }) } } diff --git a/apps/sim/tools/agiloft/create_record.ts b/apps/sim/tools/agiloft/create_record.ts index d89943f9750..f4763f55bad 100644 --- a/apps/sim/tools/agiloft/create_record.ts +++ b/apps/sim/tools/agiloft/create_record.ts @@ -72,7 +72,7 @@ export const agiloftCreateRecordTool: ToolConfig ({ url: buildCreateRecordUrl(base, params), method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, body, }), async (response) => { diff --git a/apps/sim/tools/agiloft/delete_record.ts b/apps/sim/tools/agiloft/delete_record.ts index 3796459dd64..42538104961 100644 --- a/apps/sim/tools/agiloft/delete_record.ts +++ b/apps/sim/tools/agiloft/delete_record.ts @@ -60,6 +60,7 @@ export const agiloftDeleteRecordTool: ToolConfig ({ url: buildDeleteRecordUrl(base, params), method: 'DELETE', + headers: { Accept: 'application/json' }, }), async (response) => { if (!response.ok) { diff --git a/apps/sim/tools/agiloft/get_choice_line_id.ts b/apps/sim/tools/agiloft/get_choice_line_id.ts new file mode 100644 index 00000000000..11df1040565 --- /dev/null +++ b/apps/sim/tools/agiloft/get_choice_line_id.ts @@ -0,0 +1,130 @@ +import type { + AgiloftGetChoiceLineIdParams, + AgiloftGetChoiceLineIdResponse, +} from '@/tools/agiloft/types' +import { buildGetChoiceLineIdUrl, executeAgiloftRequest } from '@/tools/agiloft/utils' +import type { ToolConfig } from '@/tools/types' + +export const agiloftGetChoiceLineIdTool: ToolConfig< + AgiloftGetChoiceLineIdParams, + AgiloftGetChoiceLineIdResponse +> = { + id: 'agiloft_get_choice_line_id', + name: 'Agiloft Get Choice Line ID', + description: + 'Resolve the internal numeric ID of a choice-list value, for use in EWSelect WHERE clauses against choice fields.', + version: '1.0.0', + + params: { + instanceUrl: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Agiloft instance URL (e.g., https://mycompany.agiloft.com)', + }, + knowledgeBase: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Knowledge base name', + }, + login: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Agiloft username', + }, + password: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Agiloft password', + }, + table: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Table name (e.g., "case", "contracts")', + }, + fieldName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Choice field name (e.g., "priority", "status")', + }, + value: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Choice display value to resolve (e.g., "High", "Active")', + }, + }, + + request: { + url: 'https://placeholder.agiloft.com', + method: 'GET', + headers: () => ({}), + }, + + directExecution: async (params) => { + return executeAgiloftRequest( + params, + (base) => ({ + url: buildGetChoiceLineIdUrl(base, params), + method: 'GET', + headers: { Accept: 'application/json' }, + }), + async (response) => { + if (!response.ok) { + const errorText = await response.text() + return { + success: false, + output: { choiceLineId: null }, + error: `Agiloft error: ${response.status} - ${errorText}`, + } + } + + const data = (await response.json()) as Record + const result = data.result ?? data + let choiceLineId: number | null = null + + if (typeof result === 'number') { + choiceLineId = result + } else if (typeof result === 'string') { + const parsed = Number(result) + choiceLineId = Number.isFinite(parsed) ? parsed : null + } else if (typeof result === 'object' && result !== null) { + const obj = result as Record + const idVal = obj.id ?? obj.choiceLineId ?? obj.lineId + if (typeof idVal === 'number') { + choiceLineId = idVal + } else if (typeof idVal === 'string') { + const parsed = Number(idVal) + choiceLineId = Number.isFinite(parsed) ? parsed : null + } + } + + if (choiceLineId === null) { + return { + success: false, + output: { choiceLineId: null }, + error: `No choice line ID found for value "${params.value}" in field "${params.fieldName}"`, + } + } + + return { + success: data.success !== false, + output: { choiceLineId }, + } + } + ) + }, + + outputs: { + choiceLineId: { + type: 'number', + description: 'Internal numeric line ID of the choice value', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/agiloft/index.ts b/apps/sim/tools/agiloft/index.ts index 2ff7ac6f4f0..c47d18f98c2 100644 --- a/apps/sim/tools/agiloft/index.ts +++ b/apps/sim/tools/agiloft/index.ts @@ -2,6 +2,7 @@ export { agiloftAttachFileTool } from '@/tools/agiloft/attach_file' export { agiloftAttachmentInfoTool } from '@/tools/agiloft/attachment_info' export { agiloftCreateRecordTool } from '@/tools/agiloft/create_record' export { agiloftDeleteRecordTool } from '@/tools/agiloft/delete_record' +export { agiloftGetChoiceLineIdTool } from '@/tools/agiloft/get_choice_line_id' export { agiloftLockRecordTool } from '@/tools/agiloft/lock_record' export { agiloftReadRecordTool } from '@/tools/agiloft/read_record' export { agiloftRemoveAttachmentTool } from '@/tools/agiloft/remove_attachment' diff --git a/apps/sim/tools/agiloft/read_record.ts b/apps/sim/tools/agiloft/read_record.ts index c9760a70089..70b015c43bf 100644 --- a/apps/sim/tools/agiloft/read_record.ts +++ b/apps/sim/tools/agiloft/read_record.ts @@ -65,6 +65,7 @@ export const agiloftReadRecordTool: ToolConfig ({ url: buildReadRecordUrl(base, params), method: 'GET', + headers: { Accept: 'application/json' }, }), async (response) => { if (!response.ok) { diff --git a/apps/sim/tools/agiloft/remove_attachment.ts b/apps/sim/tools/agiloft/remove_attachment.ts index 3117017719f..7e9a9d6f2d4 100644 --- a/apps/sim/tools/agiloft/remove_attachment.ts +++ b/apps/sim/tools/agiloft/remove_attachment.ts @@ -67,7 +67,7 @@ export const agiloftRemoveAttachmentTool: ToolConfig< request: { url: 'https://placeholder.agiloft.com', - method: 'GET', + method: 'DELETE', headers: () => ({}), }, @@ -76,7 +76,7 @@ export const agiloftRemoveAttachmentTool: ToolConfig< params, (base) => ({ url: buildRemoveAttachmentUrl(base, params), - method: 'GET', + method: 'DELETE', }), async (response) => { const text = await response.text() diff --git a/apps/sim/tools/agiloft/saved_search.ts b/apps/sim/tools/agiloft/saved_search.ts index 8b28cbd140b..8d645d871d0 100644 --- a/apps/sim/tools/agiloft/saved_search.ts +++ b/apps/sim/tools/agiloft/saved_search.ts @@ -107,8 +107,12 @@ export const agiloftSavedSearchTool: ToolConfig< properties: { name: { type: 'string', description: 'Saved search name' }, label: { type: 'string', description: 'Saved search display label' }, - id: { type: 'string', description: 'Saved search database identifier' }, - description: { type: 'string', description: 'Saved search description' }, + id: { type: 'number', description: 'Saved search database identifier' }, + description: { + type: 'string', + description: 'Saved search description', + optional: true, + }, }, }, }, diff --git a/apps/sim/tools/agiloft/search_records.ts b/apps/sim/tools/agiloft/search_records.ts index 422140a81aa..b05465c0be5 100644 --- a/apps/sim/tools/agiloft/search_records.ts +++ b/apps/sim/tools/agiloft/search_records.ts @@ -94,45 +94,44 @@ export const agiloftSearchRecordsTool: ToolConfig< const data = (await response.json()) as Record const records: Record[] = [] + const result = (data.result ?? data) as Record - if (data.result && Array.isArray(data.result)) { - for (const item of data.result as Record[]) { + if (Array.isArray(result)) { + for (const item of result as Record[]) { records.push(item) } - } else if (Array.isArray(data)) { - for (const item of data as Record[]) { - records.push(item) - } - } else if (data.results && Array.isArray(data.results)) { - for (const item of data.results as Record[]) { - records.push(item) - } - } else if (data.records && Array.isArray(data.records)) { - for (const item of data.records as Record[]) { - records.push(item) - } - } else if (typeof data.EWREST_length === 'number') { - const count = data.EWREST_length as number - for (let i = 0; i < count; i++) { - const record: Record = {} - for (const key of Object.keys(data)) { - const match = key.match(/^EWREST_(.+)_(\d+)$/) - if (match && Number(match[2]) === i) { - record[match[1]] = data[key] + } else { + const lengthRaw = result.EWREST_length ?? data.EWREST_length + const count = typeof lengthRaw === 'string' ? Number(lengthRaw) : (lengthRaw as number) + if (typeof count === 'number' && Number.isFinite(count)) { + const source = (result.EWREST_length != null ? result : data) as Record + for (let i = 0; i < count; i++) { + const record: Record = {} + for (const key of Object.keys(source)) { + const match = key.match(/^EWREST_(.+)_(\d+)$/) + if (match && Number(match[2]) === i) { + record[match[1]] = source[key] + } + } + if (Object.keys(record).length > 0) { + records.push(record) } - } - if (Object.keys(record).length > 0) { - records.push(record) } } } - const totalCount = - (data.totalCount as number) ?? - (data.total as number) ?? - (data.count as number) ?? - (data.EWREST_length as number) ?? + const totalCountRaw = + result.totalCount ?? + result.total ?? + result.count ?? + result.EWREST_length ?? + data.totalCount ?? + data.total ?? + data.count ?? + data.EWREST_length ?? records.length + const totalCount = + typeof totalCountRaw === 'string' ? Number(totalCountRaw) : (totalCountRaw as number) const page = params.page ? Number(params.page) : 0 const limit = params.limit ? Number(params.limit) : 25 diff --git a/apps/sim/tools/agiloft/select_records.ts b/apps/sim/tools/agiloft/select_records.ts index 521ea497fbd..de4be3139cb 100644 --- a/apps/sim/tools/agiloft/select_records.ts +++ b/apps/sim/tools/agiloft/select_records.ts @@ -95,14 +95,22 @@ export const agiloftSelectRecordsTool: ToolConfig< } } - const totalCount = - data.EWREST_id_length ?? data.totalCount ?? data.total ?? data.count ?? recordIds.length + const totalCountRaw = + result.EWREST_id_length ?? + result.totalCount ?? + result.total ?? + result.count ?? + data.EWREST_id_length ?? + data.totalCount ?? + data.total ?? + data.count ?? + recordIds.length return { success: data.success !== false, output: { recordIds, - totalCount: Number(totalCount), + totalCount: Number(totalCountRaw), }, } } diff --git a/apps/sim/tools/agiloft/types.ts b/apps/sim/tools/agiloft/types.ts index 9d132631556..849c6ab05c9 100644 --- a/apps/sim/tools/agiloft/types.ts +++ b/apps/sim/tools/agiloft/types.ts @@ -160,3 +160,14 @@ export interface AgiloftRemoveAttachmentResponse extends ToolResponse { remainingAttachments: number } } + +export interface AgiloftGetChoiceLineIdParams extends AgiloftBaseParams { + fieldName: string + value: string +} + +export interface AgiloftGetChoiceLineIdResponse extends ToolResponse { + output: { + choiceLineId: number | null + } +} diff --git a/apps/sim/tools/agiloft/update_record.ts b/apps/sim/tools/agiloft/update_record.ts index 0c3f8a2d096..661be1b3a8a 100644 --- a/apps/sim/tools/agiloft/update_record.ts +++ b/apps/sim/tools/agiloft/update_record.ts @@ -78,7 +78,7 @@ export const agiloftUpdateRecordTool: ToolConfig ({ url: buildUpdateRecordUrl(base, params), method: 'PUT', - headers: { 'Content-Type': 'application/json' }, + headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, body, }), async (response) => { diff --git a/apps/sim/tools/agiloft/utils.ts b/apps/sim/tools/agiloft/utils.ts index 252dcb4a819..47184deb5fb 100644 --- a/apps/sim/tools/agiloft/utils.ts +++ b/apps/sim/tools/agiloft/utils.ts @@ -4,6 +4,7 @@ import type { AgiloftAttachmentInfoParams, AgiloftBaseParams, AgiloftDeleteRecordParams, + AgiloftGetChoiceLineIdParams, AgiloftLockRecordParams, AgiloftReadRecordParams, AgiloftRemoveAttachmentParams, @@ -243,6 +244,15 @@ export function buildAttachFileUrl( return `${base}/ewws/EWAttach?$KB=${kb}&$table=${table}&$lang=en&id=${recordId}&field=${fieldName}&fileName=${encodedFileName}` } +export function buildGetChoiceLineIdUrl( + base: string, + params: AgiloftGetChoiceLineIdParams +): string { + const field = encodeURIComponent(params.fieldName.trim()) + const value = encodeURIComponent(params.value.trim()) + return `${base}/ewws/EWGetChoiceLineId/.json?${buildEwBaseQuery(params)}&field=${field}&value=${value}` +} + export function getLockHttpMethod(lockAction: string): HttpMethod { switch (lockAction) { case 'lock': diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 9130ac52dee..6bc8feea7e3 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -60,6 +60,7 @@ import { agiloftAttachmentInfoTool, agiloftCreateRecordTool, agiloftDeleteRecordTool, + agiloftGetChoiceLineIdTool, agiloftLockRecordTool, agiloftReadRecordTool, agiloftRemoveAttachmentTool, @@ -3003,6 +3004,7 @@ export const tools: Record = { agiloft_attachment_info: agiloftAttachmentInfoTool, agiloft_create_record: agiloftCreateRecordTool, agiloft_delete_record: agiloftDeleteRecordTool, + agiloft_get_choice_line_id: agiloftGetChoiceLineIdTool, agiloft_lock_record: agiloftLockRecordTool, agiloft_read_record: agiloftReadRecordTool, agiloft_remove_attachment: agiloftRemoveAttachmentTool,