@credal/actions 0.2.147 → 0.2.148

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7951,6 +7951,10 @@ export const googlemailSearchGmailMessagesDefinition = {
7951
7951
  type: "number",
7952
7952
  description: "Maximum number of messages to return (optional)",
7953
7953
  },
7954
+ timeout: {
7955
+ type: "number",
7956
+ description: "Timeout for the query in seconds (optional)",
7957
+ },
7954
7958
  },
7955
7959
  },
7956
7960
  output: {
@@ -5091,12 +5091,15 @@ export type googleOauthQueryGoogleBigQueryFunction = ActionFunction<googleOauthQ
5091
5091
  export declare const googlemailSearchGmailMessagesParamsSchema: z.ZodObject<{
5092
5092
  query: z.ZodString;
5093
5093
  maxResults: z.ZodOptional<z.ZodNumber>;
5094
+ timeout: z.ZodOptional<z.ZodNumber>;
5094
5095
  }, "strip", z.ZodTypeAny, {
5095
5096
  query: string;
5096
5097
  maxResults?: number | undefined;
5098
+ timeout?: number | undefined;
5097
5099
  }, {
5098
5100
  query: string;
5099
5101
  maxResults?: number | undefined;
5102
+ timeout?: number | undefined;
5100
5103
  }>;
5101
5104
  export type googlemailSearchGmailMessagesParamsType = z.infer<typeof googlemailSearchGmailMessagesParamsSchema>;
5102
5105
  export declare const googlemailSearchGmailMessagesOutputSchema: z.ZodObject<{
@@ -2943,6 +2943,7 @@ export const googleOauthQueryGoogleBigQueryOutputSchema = z.object({
2943
2943
  export const googlemailSearchGmailMessagesParamsSchema = z.object({
2944
2944
  query: z.string().describe('Gmail search query (e.g. "from:alice subject:urgent")'),
2945
2945
  maxResults: z.number().describe("Maximum number of messages to return (optional)").optional(),
2946
+ timeout: z.number().describe("Timeout for the query in seconds (optional)").optional(),
2946
2947
  });
2947
2948
  export const googlemailSearchGmailMessagesOutputSchema = z.object({
2948
2949
  success: z.boolean(),
@@ -1,4 +1,4 @@
1
- import { genericFillTemplateDefinition, confluenceOverwritePageDefinition, googlemapsValidateAddressDefinition, mathAddDefinition, mongoInsertMongoDocDefinition, slackSendMessageDefinition, slackGetChannelMessagesDefinition, slackCreateChannelDefinition, slackArchiveChannelDefinition, snowflakeGetRowByFieldValueDefinition, zendeskCreateZendeskTicketDefinition, zendeskListZendeskTicketsDefinition, zendeskGetTicketDetailsDefinition, zendeskUpdateTicketStatusDefinition, zendeskAddCommentToTicketDefinition, zendeskAssignTicketDefinition, openstreetmapGetLatitudeLongitudeFromLocationDefinition, nwsGetForecastForLocationDefinition, jiraAssignJiraTicketDefinition, jiraCommentJiraTicketDefinition, jiraCreateJiraTicketDefinition, jiraGetJiraTicketDetailsDefinition, jiraGetJiraTicketHistoryDefinition, jiraUpdateJiraTicketDetailsDefinition, jiraUpdateJiraTicketStatusDefinition, jiraGetServiceDesksDefinition, jiraCreateServiceDeskRequestDefinition, googlemapsNearbysearchRestaurantsDefinition, firecrawlScrapeUrlDefinition, resendSendEmailDefinition, linkedinCreateShareLinkedinPostUrlDefinition, googleOauthCreateNewGoogleDocDefinition, xCreateShareXPostUrlDefinition, firecrawlScrapeTweetDataWithNitterDefinition, finnhubSymbolLookupDefinition, finnhubGetBasicFinancialsDefinition, confluenceFetchPageContentDefinition, snowflakeRunSnowflakeQueryDefinition, lookerEnableUserByEmailDefinition, googleOauthUpdateDocDefinition, googleOauthScheduleCalendarMeetingDefinition, googleOauthListCalendarsDefinition, googleOauthListCalendarEventsDefinition, googleOauthUpdateCalendarEventDefinition, googleOauthDeleteCalendarEventDefinition, googleOauthCreateSpreadsheetDefinition, googleOauthUpdateSpreadsheetDefinition, googleOauthCreatePresentationDefinition, googleOauthUpdatePresentationDefinition, googleOauthSearchDriveByKeywordsDefinition, googlemailSearchGmailMessagesDefinition, googlemailListGmailThreadsDefinition, googleOauthListGroupsDefinition, googleOauthGetGroupDefinition, googleOauthListGroupMembersDefinition, googleOauthHasGroupMemberDefinition, googleOauthAddGroupMemberDefinition, googleOauthDeleteGroupMemberDefinition, salesforceUpdateRecordDefinition, salesforceCreateCaseDefinition, salesforceGenerateSalesReportDefinition, salesforceGetRecordDefinition, salesforceGetSalesforceRecordsByQueryDefinition, microsoftMessageTeamsChatDefinition, microsoftMessageTeamsChannelDefinition, asanaCommentTaskDefinition, asanaCreateTaskDefinition, asanaUpdateTaskDefinition, asanaSearchTasksDefinition, githubCreateOrUpdateFileDefinition, githubCreateBranchDefinition, githubCreatePullRequestDefinition, microsoftUpdateSpreadsheetDefinition, microsoftUpdateDocumentDefinition, microsoftCreateDocumentDefinition, microsoftGetDocumentDefinition, salesforceFetchSalesforceSchemaByObjectDefinition, firecrawlDeepResearchDefinition, jiraGetJiraIssuesByQueryDefinition, githubListPullRequestsDefinition, salesforceCreateRecordDefinition, ashbyCreateNoteDefinition, ashbyGetCandidateInfoDefinition, ashbyListCandidatesDefinition, ashbyListCandidateNotesDefinition, ashbySearchCandidatesDefinition, ashbyCreateCandidateDefinition, ashbyUpdateCandidateDefinition, ashbyAddCandidateToProjectDefinition, bingGetTopNSearchResultUrlsDefinition, gongGetGongTranscriptsDefinition, kandjiGetFVRecoveryKeyForDeviceDefinition, asanaListAsanaTasksByProjectDefinition, notionSearchByTitleDefinition, asanaGetTasksDetailsDefinition, linearGetIssueDetailsDefinition, linearGetProjectsDefinition, linearGetProjectDetailsDefinition, linearGetTeamDetailsDefinition, linearGetTeamsDefinition, jamfGetJamfComputerInventoryDefinition, jamfGetJamfFileVaultRecoveryKeyDefinition, oktaListOktaUsersDefinition, oktaGetOktaUserDefinition, oktaListOktaUserGroupsDefinition, oktaListOktaGroupsDefinition, oktaGetOktaGroupDefinition, oktaListOktaGroupMembersDefinition, oktaRemoveUserFromGroupDefinition, oktaAddUserToGroupDefinition, oktaResetPasswordDefinition, oktaResetMFADefinition, oktaListMFADefinition, jamfGetJamfUserComputerIdDefinition, jamfLockJamfComputerByIdDefinition, oktaTriggerOktaWorkflowDefinition, jiraOrgAssignJiraTicketDefinition, jiraOrgCreateJiraTicketDefinition, jiraOrgCommentJiraTicketDefinition, jiraOrgGetJiraTicketDetailsDefinition, jiraOrgGetJiraTicketHistoryDefinition, jiraOrgUpdateJiraTicketDetailsDefinition, jiraOrgUpdateJiraTicketStatusDefinition, jiraOrgGetJiraIssuesByQueryDefinition, googleOauthGetDriveFileContentByIdDefinition, googleOauthSearchDriveByQueryDefinition, googleOauthSearchDriveByQueryAndGetFileContentDefinition, githubGetFileContentDefinition, githubListDirectoryDefinition, } from "./autogen/templates.js";
1
+ import { genericFillTemplateDefinition, confluenceOverwritePageDefinition, googlemapsValidateAddressDefinition, mathAddDefinition, mongoInsertMongoDocDefinition, slackSendMessageDefinition, slackGetChannelMessagesDefinition, slackCreateChannelDefinition, slackArchiveChannelDefinition, snowflakeGetRowByFieldValueDefinition, zendeskCreateZendeskTicketDefinition, zendeskListZendeskTicketsDefinition, zendeskGetTicketDetailsDefinition, zendeskUpdateTicketStatusDefinition, zendeskAddCommentToTicketDefinition, zendeskAssignTicketDefinition, openstreetmapGetLatitudeLongitudeFromLocationDefinition, nwsGetForecastForLocationDefinition, jiraAssignJiraTicketDefinition, jiraCommentJiraTicketDefinition, jiraCreateJiraTicketDefinition, jiraGetJiraTicketDetailsDefinition, jiraGetJiraTicketHistoryDefinition, jiraUpdateJiraTicketDetailsDefinition, jiraUpdateJiraTicketStatusDefinition, jiraGetServiceDesksDefinition, jiraCreateServiceDeskRequestDefinition, googlemapsNearbysearchRestaurantsDefinition, firecrawlScrapeUrlDefinition, resendSendEmailDefinition, linkedinCreateShareLinkedinPostUrlDefinition, googleOauthCreateNewGoogleDocDefinition, xCreateShareXPostUrlDefinition, firecrawlScrapeTweetDataWithNitterDefinition, finnhubSymbolLookupDefinition, finnhubGetBasicFinancialsDefinition, confluenceFetchPageContentDefinition, snowflakeRunSnowflakeQueryDefinition, lookerEnableUserByEmailDefinition, googleOauthUpdateDocDefinition, googleOauthScheduleCalendarMeetingDefinition, googleOauthListCalendarsDefinition, googleOauthListCalendarEventsDefinition, googleOauthUpdateCalendarEventDefinition, googleOauthDeleteCalendarEventDefinition, googleOauthCreateSpreadsheetDefinition, googleOauthUpdateSpreadsheetDefinition, googleOauthCreatePresentationDefinition, googleOauthUpdatePresentationDefinition, googleOauthSearchDriveByKeywordsDefinition, googlemailSearchGmailMessagesDefinition, googlemailListGmailThreadsDefinition, googleOauthListGroupsDefinition, googleOauthGetGroupDefinition, googleOauthListGroupMembersDefinition, googleOauthHasGroupMemberDefinition, googleOauthAddGroupMemberDefinition, googleOauthDeleteGroupMemberDefinition, salesforceUpdateRecordDefinition, salesforceCreateCaseDefinition, salesforceGenerateSalesReportDefinition, salesforceGetRecordDefinition, salesforceGetSalesforceRecordsByQueryDefinition, microsoftMessageTeamsChatDefinition, microsoftMessageTeamsChannelDefinition, asanaCommentTaskDefinition, asanaCreateTaskDefinition, asanaUpdateTaskDefinition, asanaSearchTasksDefinition, githubCreateOrUpdateFileDefinition, githubCreateBranchDefinition, githubCreatePullRequestDefinition, microsoftUpdateSpreadsheetDefinition, microsoftUpdateDocumentDefinition, microsoftCreateDocumentDefinition, microsoftGetDocumentDefinition, salesforceFetchSalesforceSchemaByObjectDefinition, firecrawlDeepResearchDefinition, jiraGetJiraIssuesByQueryDefinition, githubListPullRequestsDefinition, salesforceCreateRecordDefinition, ashbyCreateNoteDefinition, ashbyGetCandidateInfoDefinition, ashbyListCandidatesDefinition, ashbyListCandidateNotesDefinition, ashbySearchCandidatesDefinition, ashbyCreateCandidateDefinition, ashbyUpdateCandidateDefinition, ashbyAddCandidateToProjectDefinition, bingGetTopNSearchResultUrlsDefinition, gongGetGongTranscriptsDefinition, kandjiGetFVRecoveryKeyForDeviceDefinition, asanaListAsanaTasksByProjectDefinition, notionSearchByTitleDefinition, asanaGetTasksDetailsDefinition, jamfGetJamfComputerInventoryDefinition, jamfGetJamfFileVaultRecoveryKeyDefinition, oktaListOktaUsersDefinition, oktaGetOktaUserDefinition, oktaListOktaUserGroupsDefinition, oktaListOktaGroupsDefinition, oktaGetOktaGroupDefinition, oktaListOktaGroupMembersDefinition, oktaRemoveUserFromGroupDefinition, oktaAddUserToGroupDefinition, oktaResetPasswordDefinition, oktaResetMFADefinition, oktaListMFADefinition, jamfGetJamfUserComputerIdDefinition, jamfLockJamfComputerByIdDefinition, oktaTriggerOktaWorkflowDefinition, jiraOrgAssignJiraTicketDefinition, jiraOrgCreateJiraTicketDefinition, jiraOrgCommentJiraTicketDefinition, jiraOrgGetJiraTicketDetailsDefinition, jiraOrgGetJiraTicketHistoryDefinition, jiraOrgUpdateJiraTicketDetailsDefinition, jiraOrgUpdateJiraTicketStatusDefinition, jiraOrgGetJiraIssuesByQueryDefinition, googleOauthGetDriveFileContentByIdDefinition, googleOauthSearchDriveByQueryDefinition, } from "./autogen/templates.js";
2
2
  export const ACTION_GROUPS = {
3
3
  GENERIC: {
4
4
  description: "Generic utility actions",
@@ -47,7 +47,6 @@ export const ACTION_GROUPS = {
47
47
  googleOauthUpdatePresentationDefinition,
48
48
  googleOauthSearchDriveByKeywordsDefinition,
49
49
  googleOauthSearchDriveByQueryDefinition,
50
- googleOauthSearchDriveByQueryAndGetFileContentDefinition,
51
50
  googleOauthGetDriveFileContentByIdDefinition,
52
51
  ],
53
52
  },
@@ -199,8 +198,6 @@ export const ACTION_GROUPS = {
199
198
  githubCreateBranchDefinition,
200
199
  githubCreatePullRequestDefinition,
201
200
  githubListPullRequestsDefinition,
202
- githubGetFileContentDefinition,
203
- githubListDirectoryDefinition,
204
201
  ],
205
202
  },
206
203
  ASHBY: {
@@ -248,14 +245,4 @@ export const ACTION_GROUPS = {
248
245
  oktaTriggerOktaWorkflowDefinition,
249
246
  ],
250
247
  },
251
- LINEAR: {
252
- description: "Actions for interacting with Linear",
253
- actions: [
254
- linearGetIssueDetailsDefinition,
255
- linearGetProjectsDefinition,
256
- linearGetProjectDetailsDefinition,
257
- linearGetTeamDetailsDefinition,
258
- linearGetTeamsDefinition,
259
- ],
260
- },
261
248
  };
@@ -16,6 +16,8 @@ import { read, utils } from "xlsx";
16
16
  import officeParser from "officeparser";
17
17
  const BASE_WEB_URL = "https://drive.google.com/file/d/";
18
18
  const BASE_API_URL = "https://www.googleapis.com/drive/v3/files/";
19
+ const NEWLINE_REGEX = /\r?\n+/g;
20
+ const WHITESPACE_REGEX = / +/g;
19
21
  const getDriveFileContentById = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
20
22
  var _b, _c, _d, _e;
21
23
  if (!authParams.authToken) {
@@ -31,7 +33,10 @@ const getDriveFileContentById = (_a) => __awaiter(void 0, [_a], void 0, function
31
33
  `?fields=name,mimeType,size,driveId,parents,` +
32
34
  `shortcutDetails(targetId,targetMimeType)` +
33
35
  `&supportsAllDrives=true`;
34
- const res = yield axiosClient.get(metaUrl, { headers });
36
+ const res = yield axiosClient.get(metaUrl, {
37
+ headers,
38
+ timeout: timeoutLimit,
39
+ });
35
40
  return res.data;
36
41
  });
37
42
  try {
@@ -97,15 +102,8 @@ const getDriveFileContentById = (_a) => __awaiter(void 0, [_a], void 0, function
97
102
  };
98
103
  }
99
104
  }
100
- else if (mimeType === "text/plain" || mimeType === "text/html" || mimeType === "application/rtf") {
101
- const downloadUrl = `${BASE_API_URL}${encodeURIComponent(params.fileId)}?alt=media${sharedDriveParam}`;
102
- const downloadRes = yield axiosClient.get(downloadUrl, {
103
- headers,
104
- responseType: "text",
105
- });
106
- content = downloadRes.data;
107
- }
108
105
  else if (mimeType === "text/plain" ||
106
+ mimeType === "text/html" ||
109
107
  mimeType === "text/csv" ||
110
108
  mimeType === "text/tab-separated-values" ||
111
109
  mimeType === "application/rtf" ||
@@ -113,11 +111,9 @@ const getDriveFileContentById = (_a) => __awaiter(void 0, [_a], void 0, function
113
111
  const downloadUrl = `${BASE_API_URL}${encodeURIComponent(params.fileId)}?alt=media${sharedDriveParam}`;
114
112
  const downloadRes = yield axiosClient.get(downloadUrl, {
115
113
  headers,
116
- responseType: "arraybuffer",
114
+ responseType: "text",
117
115
  });
118
- const bufferResults = downloadRes.data;
119
- const rawContentBuffer = Buffer.from(bufferResults); // Convert rawContent ArrayBuffer to Buffer
120
- content = rawContentBuffer.toString("utf-8");
116
+ content = downloadRes.data;
121
117
  }
122
118
  else if (mimeType === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ||
123
119
  mimeType === "application/vnd.ms-excel") {
@@ -127,16 +123,21 @@ const getDriveFileContentById = (_a) => __awaiter(void 0, [_a], void 0, function
127
123
  responseType: "arraybuffer",
128
124
  });
129
125
  // 1. Read the buffer into a workbook
130
- const workbook = read(downloadRes.data, { type: "buffer" });
126
+ const workbook = read(downloadRes.data, { type: "buffer", sheetStubs: false });
127
+ // Convert sheets to CSV with early termination if charLimit is set
128
+ const sheetTexts = [];
129
+ let totalLength = 0;
130
+ const effectiveLimit = charLimit ? charLimit * 1.5 : 100000; // Process 1.5x limit for safety
131
131
  // 2. Convert all sheets to plain text (CSV-style)
132
- let textOutput = "";
133
- workbook.SheetNames.forEach(sheetName => {
132
+ for (const sheetName of workbook.SheetNames) {
133
+ if (totalLength >= effectiveLimit)
134
+ break; // Early termination
134
135
  const sheet = workbook.Sheets[sheetName];
135
- const csv = utils.sheet_to_csv(sheet); // or sheet_to_json if you want arrays
136
- textOutput += `\n--- Sheet: ${sheetName} ---\n${csv}`;
137
- });
138
- // textOutput now contains all sheet data as text
139
- content = textOutput.trim();
136
+ const csv = utils.sheet_to_csv(sheet);
137
+ sheetTexts.push(`--- Sheet: ${sheetName} ---\n${csv}`);
138
+ totalLength += csv.length;
139
+ }
140
+ content = sheetTexts.join("\n").trim();
140
141
  }
141
142
  else if (mimeType === "application/vnd.openxmlformats-officedocument.presentationml.presentation") {
142
143
  // Handle modern PowerPoint files (.pptx only)
@@ -160,14 +161,10 @@ const getDriveFileContentById = (_a) => __awaiter(void 0, [_a], void 0, function
160
161
  else {
161
162
  return { success: false, error: `Unsupported file type: ${mimeType}` };
162
163
  }
163
- // 5) normalize whitespace + apply content limit
164
- content = (content !== null && content !== void 0 ? content : "")
165
- .trim()
166
- .replace(/\r?\n+/g, " ")
167
- .replace(/ +/g, " ");
164
+ // 5) Apply content limit early, then normalize whitespace
168
165
  const originalLength = content.length;
166
+ content = content.trim().replace(NEWLINE_REGEX, " ").replace(WHITESPACE_REGEX, " ");
169
167
  if (charLimit && content.length > charLimit) {
170
- // TODO in the future do this around the most valuable snippet of the doc?
171
168
  content = content.slice(0, charLimit);
172
169
  }
173
170
  return {
@@ -1,3 +1,17 @@
1
+ export interface GmailMessageResult {
2
+ id: string;
3
+ threadId: string;
4
+ snippet: string;
5
+ labelIds?: string[];
6
+ internalDate: string;
7
+ emailBody: string;
8
+ from?: string;
9
+ to?: string;
10
+ subject?: string;
11
+ cc?: string;
12
+ bcc?: string;
13
+ error?: string;
14
+ }
1
15
  import type { googlemailSearchGmailMessagesFunction } from "../../autogen/types.js";
2
16
  declare const searchGmailMessages: googlemailSearchGmailMessagesFunction;
3
17
  export default searchGmailMessages;
@@ -15,12 +15,16 @@ const MAX_EMAIL_CONTENTS_FETCHED = 50;
15
15
  const DEFAULT_EMAIL_CONTENTS_FETCHED = 25;
16
16
  const MAX_RESULTS_PER_REQUEST = 100;
17
17
  const MAX_EMAILS_FETCHED_CONCURRENTLY = 5;
18
+ const DEFAULT_EMAIL_FETCH_TIMEOUT = 5000; // 5 second timeout per email
18
19
  const limiter = new RateLimiter({ tokensPerInterval: MAX_EMAILS_FETCHED_CONCURRENTLY, interval: "second" });
20
+ const QUOTED_REPLY_REGEX = /^>.*$/gm;
21
+ const NEWLINE_NORMALIZE_REGEX = /\r\n|\r/g;
22
+ const MULTIPLE_NEWLINES_REGEX = /\n{3,}/g;
19
23
  function cleanAndTruncateEmail(text, maxLength = 2000) {
20
24
  if (!text)
21
25
  return "";
22
- // Remove quoted replies (naive)
23
- text = text.replace(/^>.*$/gm, "");
26
+ // Remove quoted replies
27
+ text = text.replace(QUOTED_REPLY_REGEX, "");
24
28
  // Remove signatures
25
29
  const signatureMarkers = ["\nBest", "\nRegards", "\nThanks", "\nSincerely"];
26
30
  for (const marker of signatureMarkers) {
@@ -31,17 +35,14 @@ function cleanAndTruncateEmail(text, maxLength = 2000) {
31
35
  }
32
36
  }
33
37
  // Normalize whitespace
34
- text = text
35
- .replace(/\r\n|\r/g, "\n")
36
- .replace(/\n{3,}/g, "\n\n")
37
- .trim();
38
+ text = text.replace(NEWLINE_NORMALIZE_REGEX, "\n").replace(MULTIPLE_NEWLINES_REGEX, "\n\n").trim();
38
39
  return text.slice(0, maxLength).trim();
39
40
  }
40
41
  const searchGmailMessages = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
41
42
  if (!authParams.authToken) {
42
43
  return { success: false, error: MISSING_AUTH_TOKEN, messages: [] };
43
44
  }
44
- const { query, maxResults } = params;
45
+ const { query, maxResults, timeout } = params;
45
46
  const max = Math.min(maxResults !== null && maxResults !== void 0 ? maxResults : DEFAULT_EMAIL_CONTENTS_FETCHED, MAX_EMAIL_CONTENTS_FETCHED);
46
47
  const allMessages = [];
47
48
  const errorMessages = [];
@@ -49,9 +50,11 @@ const searchGmailMessages = (_a) => __awaiter(void 0, [_a], void 0, function* ({
49
50
  let fetched = 0;
50
51
  try {
51
52
  while (fetched < max) {
52
- const url = `https://gmail.googleapis.com/gmail/v1/users/me/messages?q=${encodeURIComponent(query)}` +
53
- (pageToken ? `&pageToken=${encodeURIComponent(pageToken)}` : "") +
54
- `&maxResults=${Math.min(MAX_RESULTS_PER_REQUEST, max - fetched)}`;
53
+ // Calculate the optimal batch size for this request
54
+ const batchSize = Math.min(MAX_RESULTS_PER_REQUEST, // API maximum
55
+ max - fetched, // Only fetch what we still need
56
+ MAX_EMAILS_FETCHED_CONCURRENTLY);
57
+ const url = `https://gmail.googleapis.com/gmail/v1/users/me/messages?q=${encodeURIComponent(query)}&maxResults=${batchSize}${pageToken ? `&pageToken=${encodeURIComponent(pageToken)}` : ""}`;
55
58
  const listRes = yield axiosClient.get(url, {
56
59
  headers: { Authorization: `Bearer ${authParams.authToken}` },
57
60
  });
@@ -59,35 +62,42 @@ const searchGmailMessages = (_a) => __awaiter(void 0, [_a], void 0, function* ({
59
62
  if (!Array.isArray(messageList) || messageList.length === 0)
60
63
  break;
61
64
  const batch = messageList.slice(0, max - allMessages.length);
62
- const results = yield Promise.all(batch.map((msg) => __awaiter(void 0, void 0, void 0, function* () {
65
+ const results = yield Promise.allSettled(batch.map((msg) => __awaiter(void 0, void 0, void 0, function* () {
63
66
  try {
64
67
  yield limiter.removeTokens(1);
65
68
  const msgRes = yield axiosClient.get(`https://gmail.googleapis.com/gmail/v1/users/me/messages/${msg.id}?format=full`, {
66
69
  headers: { Authorization: `Bearer ${authParams.authToken}` },
70
+ timeout: timeout ? timeout * 1000 : DEFAULT_EMAIL_FETCH_TIMEOUT,
67
71
  validateStatus: () => true,
68
72
  });
69
73
  const { id, threadId, snippet, labelIds, internalDate, payload } = msgRes.data;
70
- // Find the "From" header
71
- const fromHeader = payload.headers.find(h => h.name.toLowerCase() === "from");
72
- const toHeader = payload.headers.find(h => h.name.toLowerCase() === "to");
73
- const subjectHeader = payload.headers.find(h => h.name.toLowerCase() === "subject");
74
- const ccHeader = payload.headers.find(h => h.name.toLowerCase() === "cc");
75
- const bccHeader = payload.headers.find(h => h.name.toLowerCase() === "bcc");
74
+ const headers = {};
75
+ for (const header of payload.headers) {
76
+ const lowerName = header.name.toLowerCase();
77
+ if (lowerName === "from" ||
78
+ lowerName === "to" ||
79
+ lowerName === "subject" ||
80
+ lowerName === "cc" ||
81
+ lowerName === "bcc") {
82
+ headers[lowerName] = header.value;
83
+ }
84
+ }
76
85
  const rawBody = getEmailContent(msgRes.data) || "";
77
86
  const emailBody = cleanAndTruncateEmail(rawBody);
78
- return {
87
+ const message = {
79
88
  id,
80
89
  threadId,
81
90
  snippet,
82
91
  labelIds,
83
92
  internalDate,
84
93
  emailBody,
85
- from: fromHeader === null || fromHeader === void 0 ? void 0 : fromHeader.value,
86
- to: toHeader === null || toHeader === void 0 ? void 0 : toHeader.value,
87
- subject: subjectHeader === null || subjectHeader === void 0 ? void 0 : subjectHeader.value,
88
- cc: ccHeader === null || ccHeader === void 0 ? void 0 : ccHeader.value,
89
- bcc: bccHeader === null || bccHeader === void 0 ? void 0 : bccHeader.value,
94
+ from: headers.from,
95
+ to: headers.to,
96
+ subject: headers.subject,
97
+ cc: headers.cc,
98
+ bcc: headers.bcc,
90
99
  };
100
+ return message;
91
101
  }
92
102
  catch (err) {
93
103
  const errorMessage = err instanceof Error ? err.message : "Failed to fetch message details";
@@ -108,7 +118,15 @@ const searchGmailMessages = (_a) => __awaiter(void 0, [_a], void 0, function* ({
108
118
  };
109
119
  }
110
120
  })));
111
- allMessages.push(...results);
121
+ const successfulResults = results
122
+ .filter((r) => r.status === "fulfilled")
123
+ .map(r => r.value);
124
+ const failedResults = results.filter((r) => r.status === "rejected");
125
+ failedResults.forEach(r => {
126
+ const errorMessage = r.reason instanceof Error ? r.reason.message : "Failed to fetch message details";
127
+ errorMessages.push(errorMessage);
128
+ });
129
+ allMessages.push(...successfulResults);
112
130
  fetched = allMessages.length;
113
131
  if (!nextPageToken || fetched >= max)
114
132
  break;
@@ -0,0 +1,3 @@
1
+ import { salesforceGetSalesforceRecordsByQueryFunction } from "../../autogen/types";
2
+ declare const getSalesforceRecordByQuery: salesforceGetSalesforceRecordsByQueryFunction;
3
+ export default getSalesforceRecordByQuery;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const axiosClient_1 = require("../../util/axiosClient");
13
+ const getSalesforceRecordByQuery = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
14
+ const { authToken, baseUrl } = authParams;
15
+ const { query, limit } = params;
16
+ if (!authToken || !baseUrl) {
17
+ return {
18
+ success: false,
19
+ error: "authToken and baseUrl are required for Salesforce API",
20
+ };
21
+ }
22
+ // The API limits the maximum number of records returned to 2000, the limit lets the user set a smaller custom limit
23
+ const url = `${baseUrl}/services/data/v56.0/query/?q=${encodeURIComponent(query + " LIMIT " + (limit != undefined && limit <= 2000 ? limit : 2000))}`;
24
+ try {
25
+ const response = yield axiosClient_1.axiosClient.get(url, {
26
+ headers: {
27
+ Authorization: `Bearer ${authToken}`,
28
+ },
29
+ });
30
+ return {
31
+ success: true,
32
+ records: response.data,
33
+ };
34
+ }
35
+ catch (error) {
36
+ console.error("Error retrieving Salesforce record:", error);
37
+ return {
38
+ success: false,
39
+ error: error instanceof Error ? error.message : "An unknown error occurred",
40
+ };
41
+ }
42
+ });
43
+ exports.default = getSalesforceRecordByQuery;
@@ -9,21 +9,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { WebClient } from "@slack/web-api";
11
11
  import { MISSING_AUTH_TOKEN } from "../../util/missingAuthConstants.js";
12
- import { getSlackChannels } from "./helpers.js";
13
12
  const archiveChannel = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
14
13
  if (!authParams.authToken) {
15
14
  throw new Error(MISSING_AUTH_TOKEN);
16
15
  }
17
16
  try {
18
17
  const client = new WebClient(authParams.authToken);
19
- const { channelName } = params;
20
- const allChannels = yield getSlackChannels(client);
21
- const channel = allChannels.find(channel => channel.name == channelName);
22
- if (!channel || !channel.id) {
23
- throw Error(`Channel with name ${channelName} not found`);
24
- }
25
- yield client.conversations.join({ channel: channel.id });
26
- const result = yield client.conversations.archive({ channel: channel.id });
18
+ const { channelId } = params;
19
+ const result = yield client.conversations.archive({ channel: channelId });
27
20
  if (!result.ok) {
28
21
  return {
29
22
  success: false,
@@ -22,24 +22,37 @@ class SlackUserCache {
22
22
  constructor(client) {
23
23
  this.client = client;
24
24
  this.cache = new Map();
25
+ this.pendingRequests = new Map();
25
26
  this.client = client;
26
27
  }
27
28
  get(id) {
28
29
  return __awaiter(this, void 0, void 0, function* () {
29
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
30
30
  const cached = this.cache.get(id);
31
31
  if (cached)
32
32
  return cached;
33
- const res = yield this.client.users.info({ user: id });
34
- const u = {
35
- name: (_g = (_e = (_c = (_b = (_a = res.user) === null || _a === void 0 ? void 0 : _a.profile) === null || _b === void 0 ? void 0 : _b.display_name) !== null && _c !== void 0 ? _c : (_d = res.user) === null || _d === void 0 ? void 0 : _d.real_name) !== null && _e !== void 0 ? _e : (_f = res.user) === null || _f === void 0 ? void 0 : _f.name) !== null && _g !== void 0 ? _g : "",
36
- email: (_k = (_j = (_h = res.user) === null || _h === void 0 ? void 0 : _h.profile) === null || _j === void 0 ? void 0 : _j.email) !== null && _k !== void 0 ? _k : "",
37
- };
38
- if (res.user && id) {
39
- this.cache.set(id, u);
40
- return u;
41
- }
42
- return undefined;
33
+ const pending = this.pendingRequests.get(id);
34
+ if (pending)
35
+ return pending;
36
+ const promise = (() => __awaiter(this, void 0, void 0, function* () {
37
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
38
+ try {
39
+ const res = yield this.client.users.info({ user: id });
40
+ const u = {
41
+ name: (_g = (_e = (_c = (_b = (_a = res.user) === null || _a === void 0 ? void 0 : _a.profile) === null || _b === void 0 ? void 0 : _b.display_name) !== null && _c !== void 0 ? _c : (_d = res.user) === null || _d === void 0 ? void 0 : _d.real_name) !== null && _e !== void 0 ? _e : (_f = res.user) === null || _f === void 0 ? void 0 : _f.name) !== null && _g !== void 0 ? _g : "",
42
+ email: (_k = (_j = (_h = res.user) === null || _h === void 0 ? void 0 : _h.profile) === null || _j === void 0 ? void 0 : _j.email) !== null && _k !== void 0 ? _k : "",
43
+ };
44
+ if (res.user && id) {
45
+ this.cache.set(id, u);
46
+ return u;
47
+ }
48
+ return undefined;
49
+ }
50
+ finally {
51
+ this.pendingRequests.delete(id);
52
+ }
53
+ }))();
54
+ this.pendingRequests.set(id, promise);
55
+ return promise;
43
56
  });
44
57
  }
45
58
  set(id, { email, name }) {
@@ -238,44 +251,58 @@ const searchSlack = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params,
238
251
  const targetIds = (emails === null || emails === void 0 ? void 0 : emails.length) ? yield lookupUserIdsByEmail(client, emails, cache) : [];
239
252
  const filteredTargetIds = targetIds.filter(id => id !== myUserId);
240
253
  const allMatches = [];
241
- // --- Scoped DM/MPIM searches ---
254
+ // --- Parallel search execution for better performance ---
255
+ const searchPromises = [];
256
+ // Scoped DM/MPIM searches
242
257
  if (filteredTargetIds.length === 1) {
243
- allMatches.push(...(yield searchScoped({ client, scope: `<@${filteredTargetIds[0]}>`, topic, timeRange, limit })));
258
+ searchPromises.push(searchScoped({ client, scope: `<@${filteredTargetIds[0]}>`, topic, timeRange, limit }));
244
259
  }
245
260
  else if (filteredTargetIds.length >= 2) {
246
- const mpimName = yield tryGetMPIMName(client, filteredTargetIds);
247
- if (mpimName) {
248
- allMatches.push(...(yield searchScoped({ client, scope: mpimName, topic, timeRange, limit })));
249
- }
250
- for (const id of filteredTargetIds) {
251
- allMatches.push(...(yield searchScoped({ client, scope: `<@${id}>`, topic, timeRange, limit })));
252
- }
261
+ // Run MPIM lookup and individual DM searches in parallel
262
+ const searchMPIM = () => __awaiter(void 0, void 0, void 0, function* () {
263
+ const mpimName = yield tryGetMPIMName(client, filteredTargetIds);
264
+ return mpimName ? searchScoped({ client, scope: mpimName, topic, timeRange, limit }) : [];
265
+ });
266
+ searchPromises.push(searchMPIM());
267
+ // Add individual DM searches
268
+ searchPromises.push(...filteredTargetIds.map(id => searchScoped({ client, scope: `<@${id}>`, topic, timeRange, limit })));
253
269
  }
254
270
  else if (channel) {
255
- allMatches.push(...(yield searchScoped({ client, scope: normalizeChannelOperand(channel), topic, timeRange, limit })));
271
+ searchPromises.push(searchScoped({ client, scope: normalizeChannelOperand(channel), topic, timeRange, limit }));
256
272
  }
257
- // --- Topic-wide search ---
258
- const topicMatches = topic ? yield searchByTopic({ client, topic, timeRange, limit }) : [];
259
- allMatches.push(...topicMatches);
273
+ // Topic-wide search in parallel
274
+ searchPromises.push(...(topic ? [searchByTopic({ client, topic, timeRange, limit })] : []));
275
+ // Execute all searches in parallel
276
+ const searchResults = yield Promise.all(searchPromises);
277
+ searchResults.forEach(matches => allMatches.push(...matches));
260
278
  // --- Expand hits with context + filter overlap ---
279
+ // Create a channel info cache to avoid redundant API calls
280
+ const channelInfoCache = new Map();
261
281
  const expanded = yield Promise.all(allMatches.map(m => limitHit(() => __awaiter(void 0, void 0, void 0, function* () {
262
- var _a, _b, _c, _d, _e, _f;
282
+ var _a, _b, _c, _d, _e, _f, _g, _h;
263
283
  if (!m.ts || !((_a = m.channel) === null || _a === void 0 ? void 0 : _a.id))
264
284
  return null;
265
285
  const anchor = yield fetchOneMessage(client, m.channel.id, m.ts);
266
286
  const rootTs = (anchor === null || anchor === void 0 ? void 0 : anchor.thread_ts) || m.ts;
267
287
  let members = [];
268
- // Check convo type (DM, MPIM, channel)
269
- const convoInfo = yield client.conversations.info({ channel: m.channel.id });
270
- const isIm = (_b = convoInfo.channel) === null || _b === void 0 ? void 0 : _b.is_im;
271
- const isMpim = (_c = convoInfo.channel) === null || _c === void 0 ? void 0 : _c.is_mpim;
288
+ // Check convo type (DM, MPIM, channel) with caching
289
+ let channelInfo = channelInfoCache.get(m.channel.id);
290
+ if (!channelInfo) {
291
+ const convoInfo = yield client.conversations.info({ channel: m.channel.id });
292
+ channelInfo = {
293
+ isIm: (_c = (_b = convoInfo.channel) === null || _b === void 0 ? void 0 : _b.is_im) !== null && _c !== void 0 ? _c : false,
294
+ isMpim: (_e = (_d = convoInfo.channel) === null || _d === void 0 ? void 0 : _d.is_mpim) !== null && _e !== void 0 ? _e : false,
295
+ };
296
+ channelInfoCache.set(m.channel.id, channelInfo);
297
+ }
298
+ const { isIm, isMpim } = channelInfo;
272
299
  const [contextMsgs, permalink] = (anchor === null || anchor === void 0 ? void 0 : anchor.thread_ts)
273
300
  ? [yield fetchThread(client, m.channel.id, rootTs), yield getPermalink(client, m.channel.id, rootTs)]
274
301
  : [yield fetchContextWindow(client, m.channel.id, m.ts), yield getPermalink(client, m.channel.id, m.ts)];
275
302
  let passesFilter = false;
276
303
  if (isIm || isMpim) {
277
304
  // DM/MPIM: use members, not authorship
278
- const membersRes = (_d = (yield client.conversations.members({ channel: m.channel.id })).members) !== null && _d !== void 0 ? _d : [];
305
+ const membersRes = (_f = (yield client.conversations.members({ channel: m.channel.id })).members) !== null && _f !== void 0 ? _f : [];
279
306
  members = yield Promise.all(membersRes.map((uid) => __awaiter(void 0, void 0, void 0, function* () {
280
307
  const u = yield cache.get(uid);
281
308
  return { userId: uid, userEmail: u === null || u === void 0 ? void 0 : u.email, userName: u === null || u === void 0 ? void 0 : u.name };
@@ -302,8 +329,8 @@ const searchSlack = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params,
302
329
  channelId: m.channel.id,
303
330
  ts: rootTs,
304
331
  text: (anchor === null || anchor === void 0 ? void 0 : anchor.text) ? yield expandSlackEntities(client, cache, anchor.text) : undefined,
305
- userEmail: (anchor === null || anchor === void 0 ? void 0 : anchor.user) ? (_e = (yield cache.get(anchor.user))) === null || _e === void 0 ? void 0 : _e.email : undefined,
306
- userName: (anchor === null || anchor === void 0 ? void 0 : anchor.user) ? (_f = (yield cache.get(anchor.user))) === null || _f === void 0 ? void 0 : _f.name : undefined,
332
+ userEmail: (anchor === null || anchor === void 0 ? void 0 : anchor.user) ? (_g = (yield cache.get(anchor.user))) === null || _g === void 0 ? void 0 : _g.email : undefined,
333
+ userName: (anchor === null || anchor === void 0 ? void 0 : anchor.user) ? (_h = (yield cache.get(anchor.user))) === null || _h === void 0 ? void 0 : _h.name : undefined,
307
334
  context,
308
335
  permalink,
309
336
  members,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@credal/actions",
3
- "version": "0.2.147",
3
+ "version": "0.2.148",
4
4
  "type": "module",
5
5
  "description": "AI Actions by Credal AI",
6
6
  "sideEffects": false,
@@ -1,3 +0,0 @@
1
- import { confluenceUpdatePageFunction } from "../../../actions/autogen/types";
2
- declare const confluenceUpdatePage: confluenceUpdatePageFunction;
3
- export default confluenceUpdatePage;
@@ -1,47 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- const axios_1 = __importDefault(require("axios"));
16
- function getConfluenceApi(baseUrl, username, apiToken) {
17
- const api = axios_1.default.create({
18
- baseURL: baseUrl,
19
- headers: {
20
- Accept: "application/json",
21
- // Tokens are associated with a specific user.
22
- Authorization: `Basic ${Buffer.from(`${username}:${apiToken}`).toString("base64")}`,
23
- },
24
- });
25
- return api;
26
- }
27
- const confluenceUpdatePage = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
28
- const { pageId, username, content, title } = params;
29
- const { baseUrl, authToken } = authParams;
30
- const api = getConfluenceApi(baseUrl, username, authToken);
31
- // Get current version number
32
- const response = yield api.get(`/api/v2/pages/${pageId}`);
33
- const currVersion = response.data.version.number;
34
- yield api.put(`/api/v2/pages/${pageId}`, {
35
- id: pageId,
36
- status: "current",
37
- title,
38
- body: {
39
- representation: "storage",
40
- value: content,
41
- },
42
- version: {
43
- number: currVersion + 1,
44
- },
45
- });
46
- });
47
- exports.default = confluenceUpdatePage;
@@ -1,8 +0,0 @@
1
- import { z } from "zod";
2
- export declare const TokenResponseSchema: z.ZodObject<{
3
- token: z.ZodString;
4
- }, "strip", z.ZodTypeAny, {
5
- token: string;
6
- }, {
7
- token: string;
8
- }>;
@@ -1,7 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TokenResponseSchema = void 0;
4
- const zod_1 = require("zod");
5
- exports.TokenResponseSchema = zod_1.z.object({
6
- token: zod_1.z.string(),
7
- });