@credal/actions 0.2.208 → 0.2.210

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.
@@ -6,7 +6,7 @@ const sendMessage = async ({ params, authParams, }) => {
6
6
  if (!authParams.authToken) {
7
7
  throw new Error(MISSING_AUTH_TOKEN);
8
8
  }
9
- const { channelId: inputChannelId, channelName, message } = params;
9
+ const { channelId: inputChannelId, channelName, message, unfurlLinks, threadTs, replyBroadcast } = params;
10
10
  if (!inputChannelId && !channelName) {
11
11
  throw Error("Either channelId or channelName must be provided");
12
12
  }
@@ -19,33 +19,74 @@ const sendMessage = async ({ params, authParams, }) => {
19
19
  if (!channelId) {
20
20
  throw Error(`Channel with name ${channelName} not found`);
21
21
  }
22
- try {
23
- // First try sending as Markdown blocks (mrkdwn)
24
- await client.chat.postMessage({
25
- channel: channelId,
26
- text: message, // Fallback text for notifications/clients that don't render blocks
27
- blocks: [
28
- {
29
- type: "section",
30
- text: {
31
- type: "mrkdwn",
32
- text: message,
33
- },
34
- },
35
- ],
22
+ const baseArgs = {
23
+ channel: channelId,
24
+ text: message,
25
+ unfurl_links: unfurlLinks,
26
+ };
27
+ const messageBlocks = [
28
+ {
29
+ type: "section",
30
+ text: {
31
+ type: "mrkdwn",
32
+ text: message,
33
+ },
34
+ },
35
+ ];
36
+ const postAsBlocks = () => client.chat.postMessage(threadTs
37
+ ? replyBroadcast
38
+ ? {
39
+ ...baseArgs,
40
+ thread_ts: threadTs,
41
+ reply_broadcast: true,
42
+ blocks: messageBlocks,
43
+ }
44
+ : {
45
+ ...baseArgs,
46
+ thread_ts: threadTs,
47
+ blocks: messageBlocks,
48
+ }
49
+ : {
50
+ ...baseArgs,
51
+ blocks: messageBlocks,
36
52
  });
53
+ const postAsPlainText = () => client.chat.postMessage(threadTs
54
+ ? replyBroadcast
55
+ ? { ...baseArgs, thread_ts: threadTs, reply_broadcast: true }
56
+ : { ...baseArgs, thread_ts: threadTs }
57
+ : baseArgs);
58
+ const buildSuccess = async (result) => {
59
+ const ts = result.ts;
60
+ const resolvedChannelId = result.channel ?? channelId;
61
+ let permalink;
62
+ if (ts) {
63
+ try {
64
+ const permalinkResult = await client.chat.getPermalink({
65
+ channel: resolvedChannelId,
66
+ message_ts: ts,
67
+ });
68
+ permalink = permalinkResult.permalink;
69
+ }
70
+ catch {
71
+ // Permalink fetch failed, but the message was sent successfully
72
+ }
73
+ }
37
74
  return slackSendMessageOutputSchema.parse({
38
75
  success: true,
76
+ channelId: resolvedChannelId,
77
+ timestamp: ts,
78
+ threadTs: threadTs,
79
+ permalink,
39
80
  });
81
+ };
82
+ try {
83
+ const result = await postAsBlocks();
84
+ return await buildSuccess(result);
40
85
  }
41
86
  catch {
42
- // On any error, retry once with plain text only (no blocks)
43
87
  try {
44
- await client.chat.postMessage({
45
- channel: channelId,
46
- text: message,
47
- });
48
- return slackSendMessageOutputSchema.parse({ success: true });
88
+ const result = await postAsPlainText();
89
+ return await buildSuccess(result);
49
90
  }
50
91
  catch (retryError) {
51
92
  return slackSendMessageOutputSchema.parse({
@@ -128,6 +128,7 @@ interface GoogleSlidesPresentation {
128
128
  };
129
129
  }
130
130
  export declare function parseGoogleDocFromRawContentToPlainText(snapshotRawContent: GoogleDocsDocument): string;
131
+ export declare function parseWorkbookBufferToPlainText(data: ArrayBuffer | Buffer, charLimit?: number): string;
131
132
  export declare function parseGoogleSheetsFromRawContentToPlainText(snapshotRawContent: GoogleSheetsSpreadsheet): string;
132
133
  export declare function parseGoogleSlidesFromRawContentToPlainText(snapshotRawContent: GoogleSlidesPresentation): string;
133
134
  export declare function getGoogleDocContent(fileId: string, authToken: string, axiosClient: AxiosInstance, sharedDriveParams: string): Promise<string>;
@@ -1,4 +1,5 @@
1
1
  import Papa from "papaparse";
2
+ import { read, utils } from "xlsx";
2
3
  import { isAxiosTimeoutError } from "../actions/util/axiosClient.js";
3
4
  // Helper function to parse Google Docs content to plain text
4
5
  export function parseGoogleDocFromRawContentToPlainText(snapshotRawContent) {
@@ -138,6 +139,23 @@ function parseCSVToSheetJson(csvData, sheetName = "Sheet1") {
138
139
  });
139
140
  return JSON.stringify([{ sheetName, headers, rows }]);
140
141
  }
142
+ export function parseWorkbookBufferToPlainText(data, charLimit) {
143
+ const workbook = read(data, { type: "buffer", sheetStubs: false });
144
+ const sheetTexts = [];
145
+ let totalLength = 0;
146
+ // charLimit here is a soft parsing budget; downstream callers may still apply a hard final slice.
147
+ const effectiveLimit = charLimit ? charLimit * 1.5 : 100_000;
148
+ for (const sheetName of workbook.SheetNames) {
149
+ if (totalLength >= effectiveLimit) {
150
+ break;
151
+ }
152
+ const sheet = workbook.Sheets[sheetName];
153
+ const csv = utils.sheet_to_csv(sheet);
154
+ sheetTexts.push(`--- Sheet: ${sheetName} ---\n${csv}`);
155
+ totalLength += csv.length;
156
+ }
157
+ return sheetTexts.join("\n").trim();
158
+ }
141
159
  export function parseGoogleSheetsFromRawContentToPlainText(snapshotRawContent) {
142
160
  if (!snapshotRawContent.sheets)
143
161
  return "[]";
@@ -317,21 +335,14 @@ export async function getGoogleDocContent(fileId, authToken, axiosClient, shared
317
335
  }
318
336
  }
319
337
  export async function getGoogleSheetContent(fileId, authToken, axiosClient, sharedDriveParams) {
320
- // Use CSV export as primary method - it's much faster and more reliable for large sheets
321
- // The Sheets API with includeGridData can timeout on large spreadsheets
338
+ // Prefer XLSX export so native Google Sheets follow the same workbook parsing path as uploaded Excel files.
322
339
  try {
323
- const exportUrl = `${GDRIVE_BASE_URL}${encodeURIComponent(fileId)}/export?mimeType=text/csv${sharedDriveParams}`;
340
+ const exportUrl = `${GDRIVE_BASE_URL}${encodeURIComponent(fileId)}/export?mimeType=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet${sharedDriveParams}`;
324
341
  const exportRes = await axiosClient.get(exportUrl, {
325
342
  headers: { Authorization: `Bearer ${authToken}` },
326
- responseType: "text",
343
+ responseType: "arraybuffer",
327
344
  });
328
- // Clean up trailing commas and convert to JSON format
329
- const cleanedCsv = exportRes.data
330
- .split("\n")
331
- .map((line) => line.replace(/,+$/, ""))
332
- .map((line) => line.replace(/,{2,}/g, ","))
333
- .join("\n");
334
- return parseCSVToSheetJson(cleanedCsv);
345
+ return parseWorkbookBufferToPlainText(exportRes.data);
335
346
  }
336
347
  catch (exportError) {
337
348
  // Check if it's a 404 or permission error
@@ -342,21 +353,36 @@ export async function getGoogleSheetContent(fileId, authToken, axiosClient, shar
342
353
  throw new Error(`Spreadsheet not accessible (${status}): ${fileId}`, { cause: exportError });
343
354
  }
344
355
  }
345
- // If CSV export fails, try the Sheets API as fallback (but this is slower)
356
+ // If XLSX export fails, fall back to the prior CSV-first behavior.
346
357
  try {
347
- const sheetsUrl = `https://sheets.googleapis.com/v4/spreadsheets/${fileId}?includeGridData=true`;
348
- const sheetsRes = await axiosClient.get(sheetsUrl, {
349
- headers: {
350
- Authorization: `Bearer ${authToken}`,
351
- },
358
+ const csvExportUrl = `${GDRIVE_BASE_URL}${encodeURIComponent(fileId)}/export?mimeType=text/csv${sharedDriveParams}`;
359
+ const csvExportRes = await axiosClient.get(csvExportUrl, {
360
+ headers: { Authorization: `Bearer ${authToken}` },
361
+ responseType: "text",
352
362
  });
353
- return parseGoogleSheetsFromRawContentToPlainText(sheetsRes.data);
363
+ const cleanedCsv = csvExportRes.data
364
+ .split("\n")
365
+ .map((line) => line.replace(/,+$/, ""))
366
+ .map((line) => line.replace(/,{2,}/g, ","))
367
+ .join("\n");
368
+ return parseCSVToSheetJson(cleanedCsv);
354
369
  }
355
- catch (sheetsError) {
356
- if (isAxiosTimeoutError(sheetsError)) {
357
- throw new Error("Request timed out using Google Sheets API", { cause: sheetsError });
370
+ catch {
371
+ try {
372
+ const sheetsUrl = `https://sheets.googleapis.com/v4/spreadsheets/${fileId}?includeGridData=true`;
373
+ const sheetsRes = await axiosClient.get(sheetsUrl, {
374
+ headers: {
375
+ Authorization: `Bearer ${authToken}`,
376
+ },
377
+ });
378
+ return parseGoogleSheetsFromRawContentToPlainText(sheetsRes.data);
379
+ }
380
+ catch (sheetsError) {
381
+ if (isAxiosTimeoutError(sheetsError)) {
382
+ throw new Error("Request timed out using Google Sheets API", { cause: sheetsError });
383
+ }
384
+ throw new Error(`Unable to access spreadsheet content: ${fileId}`, { cause: sheetsError });
358
385
  }
359
- throw new Error(`Unable to access spreadsheet content: ${fileId}`, { cause: sheetsError });
360
386
  }
361
387
  }
362
388
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@credal/actions",
3
- "version": "0.2.208",
3
+ "version": "0.2.210",
4
4
  "type": "module",
5
5
  "description": "AI Actions by Credal AI",
6
6
  "sideEffects": false,
@@ -1,3 +0,0 @@
1
- import type { jiraUpdateServiceDeskRequestFunction } from "../../autogen/types.js";
2
- declare const updateServiceDeskRequest: jiraUpdateServiceDeskRequestFunction;
3
- export default updateServiceDeskRequest;
@@ -1,72 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { axiosClient } from "../../util/axiosClient.js";
11
- const updateServiceDeskRequest = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
12
- const { issueId, requestTypeId, summary, description, priority, customFields } = params;
13
- const { authToken, cloudId, baseUrl } = authParams;
14
- if (!cloudId || !authToken) {
15
- throw new Error("Valid Cloud ID and auth token are required to update service desk request");
16
- }
17
- // Use the regular Jira API for updating service desk requests as they are still Jira issues
18
- const apiUrl = `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/issue/${issueId}`;
19
- const formattedDescription = description
20
- ? {
21
- type: "doc",
22
- version: 1,
23
- content: [
24
- {
25
- type: "paragraph",
26
- content: [
27
- {
28
- type: "text",
29
- text: description,
30
- },
31
- ],
32
- },
33
- ],
34
- }
35
- : undefined;
36
- const payload = {
37
- fields: Object.assign(Object.assign(Object.assign(Object.assign({}, (summary && { summary })), (formattedDescription && { description: formattedDescription })), (priority && { priority: { name: priority } })), (customFields && Object.assign({}, customFields))),
38
- };
39
- try {
40
- yield axiosClient.put(apiUrl, payload, {
41
- headers: {
42
- Authorization: `Bearer ${authToken}`,
43
- Accept: "application/json",
44
- "Content-Type": "application/json",
45
- },
46
- });
47
- // Get the updated issue details to return current status and web link
48
- const getResponse = yield axiosClient.get(apiUrl, {
49
- headers: {
50
- Authorization: `Bearer ${authToken}`,
51
- Accept: "application/json",
52
- },
53
- });
54
- const issueKey = getResponse.data.key;
55
- const currentStatus = getResponse.data.fields.status.name;
56
- const webLink = `${baseUrl}/browse/${issueKey}`;
57
- return {
58
- success: true,
59
- issueKey,
60
- webLink,
61
- currentStatus,
62
- };
63
- }
64
- catch (error) {
65
- console.error("Error updating service desk request:", error);
66
- return {
67
- success: false,
68
- error: error instanceof Error ? error.message : "Unknown error",
69
- };
70
- }
71
- });
72
- export default updateServiceDeskRequest;
@@ -1,3 +0,0 @@
1
- import type { microsoftSendOutlookEmailFunction } from "../../autogen/types.js";
2
- declare const sendEmail: microsoftSendOutlookEmailFunction;
3
- export default sendEmail;
@@ -1,48 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { getGraphClient } from "./utils.js";
11
- const sendEmail = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
12
- const { toRecipients, subject, body, ccRecipients, bccRecipients } = params;
13
- let client = undefined;
14
- try {
15
- client = yield getGraphClient(authParams);
16
- }
17
- catch (error) {
18
- return {
19
- success: false,
20
- error: "Error while authorizing: " + (error instanceof Error ? error.message : "Unknown error"),
21
- };
22
- }
23
- try {
24
- const message = {
25
- message: Object.assign(Object.assign({ subject, body: {
26
- contentType: "HTML",
27
- content: body,
28
- }, toRecipients: toRecipients.map(email => ({ emailAddress: { address: email } })) }, (ccRecipients && ccRecipients.length > 0
29
- ? { ccRecipients: ccRecipients.map(email => ({ emailAddress: { address: email } })) }
30
- : {})), (bccRecipients && bccRecipients.length > 0
31
- ? { bccRecipients: bccRecipients.map(email => ({ emailAddress: { address: email } })) }
32
- : {})),
33
- saveToSentItems: true,
34
- };
35
- yield client.api("/me/sendMail").post(message);
36
- return {
37
- success: true,
38
- };
39
- }
40
- catch (error) {
41
- console.error(error);
42
- return {
43
- success: false,
44
- error: "Error sending email: " + (error instanceof Error ? error.message : "Unknown error"),
45
- };
46
- }
47
- });
48
- export default sendEmail;