@copilotkit/channels-slack 0.1.0

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.
Files changed (141) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +353 -0
  3. package/dist/__tests__/assistant.test.d.ts +2 -0
  4. package/dist/__tests__/assistant.test.d.ts.map +1 -0
  5. package/dist/__tests__/assistant.test.js +153 -0
  6. package/dist/__tests__/auto-close-streaming.test.d.ts +2 -0
  7. package/dist/__tests__/auto-close-streaming.test.d.ts.map +1 -0
  8. package/dist/__tests__/auto-close-streaming.test.js +139 -0
  9. package/dist/__tests__/built-ins.test.d.ts +2 -0
  10. package/dist/__tests__/built-ins.test.d.ts.map +1 -0
  11. package/dist/__tests__/built-ins.test.js +67 -0
  12. package/dist/__tests__/chunked-message-stream.test.d.ts +2 -0
  13. package/dist/__tests__/chunked-message-stream.test.d.ts.map +1 -0
  14. package/dist/__tests__/chunked-message-stream.test.js +226 -0
  15. package/dist/__tests__/conversation-store.test.d.ts +2 -0
  16. package/dist/__tests__/conversation-store.test.d.ts.map +1 -0
  17. package/dist/__tests__/conversation-store.test.js +209 -0
  18. package/dist/__tests__/download-files.test.d.ts +2 -0
  19. package/dist/__tests__/download-files.test.d.ts.map +1 -0
  20. package/dist/__tests__/download-files.test.js +142 -0
  21. package/dist/__tests__/ephemeral.test.d.ts +2 -0
  22. package/dist/__tests__/ephemeral.test.d.ts.map +1 -0
  23. package/dist/__tests__/ephemeral.test.js +85 -0
  24. package/dist/__tests__/event-renderer.test.d.ts +2 -0
  25. package/dist/__tests__/event-renderer.test.d.ts.map +1 -0
  26. package/dist/__tests__/event-renderer.test.js +521 -0
  27. package/dist/__tests__/markdown-to-mrkdwn.test.d.ts +2 -0
  28. package/dist/__tests__/markdown-to-mrkdwn.test.d.ts.map +1 -0
  29. package/dist/__tests__/markdown-to-mrkdwn.test.js +80 -0
  30. package/dist/__tests__/message-stream.test.d.ts +2 -0
  31. package/dist/__tests__/message-stream.test.d.ts.map +1 -0
  32. package/dist/__tests__/message-stream.test.js +116 -0
  33. package/dist/__tests__/native-renderer.test.d.ts +2 -0
  34. package/dist/__tests__/native-renderer.test.d.ts.map +1 -0
  35. package/dist/__tests__/native-renderer.test.js +236 -0
  36. package/dist/__tests__/native-stream.test.d.ts +2 -0
  37. package/dist/__tests__/native-stream.test.d.ts.map +1 -0
  38. package/dist/__tests__/native-stream.test.js +235 -0
  39. package/dist/__tests__/reactions.test.d.ts +2 -0
  40. package/dist/__tests__/reactions.test.d.ts.map +1 -0
  41. package/dist/__tests__/reactions.test.js +193 -0
  42. package/dist/__tests__/slack-listener.test.d.ts +2 -0
  43. package/dist/__tests__/slack-listener.test.d.ts.map +1 -0
  44. package/dist/__tests__/slack-listener.test.js +559 -0
  45. package/dist/__tests__/views.test.d.ts +2 -0
  46. package/dist/__tests__/views.test.d.ts.map +1 -0
  47. package/dist/__tests__/views.test.js +143 -0
  48. package/dist/adapter.d.ts +188 -0
  49. package/dist/adapter.d.ts.map +1 -0
  50. package/dist/adapter.js +859 -0
  51. package/dist/adapter.test.d.ts +2 -0
  52. package/dist/adapter.test.d.ts.map +1 -0
  53. package/dist/adapter.test.js +368 -0
  54. package/dist/assistant.d.ts +19 -0
  55. package/dist/assistant.d.ts.map +1 -0
  56. package/dist/assistant.js +124 -0
  57. package/dist/auto-close-streaming.d.ts +62 -0
  58. package/dist/auto-close-streaming.d.ts.map +1 -0
  59. package/dist/auto-close-streaming.js +273 -0
  60. package/dist/built-in-context.d.ts +22 -0
  61. package/dist/built-in-context.d.ts.map +1 -0
  62. package/dist/built-in-context.js +65 -0
  63. package/dist/built-in-tools.d.ts +23 -0
  64. package/dist/built-in-tools.d.ts.map +1 -0
  65. package/dist/built-in-tools.js +45 -0
  66. package/dist/chunked-message-stream.d.ts +67 -0
  67. package/dist/chunked-message-stream.d.ts.map +1 -0
  68. package/dist/chunked-message-stream.js +134 -0
  69. package/dist/codec.d.ts +18 -0
  70. package/dist/codec.d.ts.map +1 -0
  71. package/dist/codec.js +18 -0
  72. package/dist/codec.test.d.ts +2 -0
  73. package/dist/codec.test.d.ts.map +1 -0
  74. package/dist/codec.test.js +19 -0
  75. package/dist/conversation-store.d.ts +92 -0
  76. package/dist/conversation-store.d.ts.map +1 -0
  77. package/dist/conversation-store.js +196 -0
  78. package/dist/download-files.d.ts +59 -0
  79. package/dist/download-files.d.ts.map +1 -0
  80. package/dist/download-files.js +116 -0
  81. package/dist/event-renderer.d.ts +98 -0
  82. package/dist/event-renderer.d.ts.map +1 -0
  83. package/dist/event-renderer.js +493 -0
  84. package/dist/index.d.ts +34 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +23 -0
  87. package/dist/ingress-normalize.d.ts +75 -0
  88. package/dist/ingress-normalize.d.ts.map +1 -0
  89. package/dist/ingress-normalize.js +153 -0
  90. package/dist/ingress-normalize.test.d.ts +2 -0
  91. package/dist/ingress-normalize.test.d.ts.map +1 -0
  92. package/dist/ingress-normalize.test.js +187 -0
  93. package/dist/interaction.d.ts +30 -0
  94. package/dist/interaction.d.ts.map +1 -0
  95. package/dist/interaction.js +219 -0
  96. package/dist/interaction.test.d.ts +2 -0
  97. package/dist/interaction.test.d.ts.map +1 -0
  98. package/dist/interaction.test.js +137 -0
  99. package/dist/markdown-to-mrkdwn.d.ts +21 -0
  100. package/dist/markdown-to-mrkdwn.d.ts.map +1 -0
  101. package/dist/markdown-to-mrkdwn.js +99 -0
  102. package/dist/message-stream.d.ts +44 -0
  103. package/dist/message-stream.d.ts.map +1 -0
  104. package/dist/message-stream.js +70 -0
  105. package/dist/native-stream.d.ts +131 -0
  106. package/dist/native-stream.d.ts.map +1 -0
  107. package/dist/native-stream.js +208 -0
  108. package/dist/render/block-kit.d.ts +35 -0
  109. package/dist/render/block-kit.d.ts.map +1 -0
  110. package/dist/render/block-kit.js +399 -0
  111. package/dist/render/block-kit.test.d.ts +2 -0
  112. package/dist/render/block-kit.test.d.ts.map +1 -0
  113. package/dist/render/block-kit.test.js +289 -0
  114. package/dist/render/budget.d.ts +24 -0
  115. package/dist/render/budget.d.ts.map +1 -0
  116. package/dist/render/budget.js +30 -0
  117. package/dist/render/budget.test.d.ts +2 -0
  118. package/dist/render/budget.test.d.ts.map +1 -0
  119. package/dist/render/budget.test.js +49 -0
  120. package/dist/render/modal.d.ts +13 -0
  121. package/dist/render/modal.d.ts.map +1 -0
  122. package/dist/render/modal.js +108 -0
  123. package/dist/render/transport.d.ts +42 -0
  124. package/dist/render/transport.d.ts.map +1 -0
  125. package/dist/render/transport.js +1 -0
  126. package/dist/render.d.ts +23 -0
  127. package/dist/render.d.ts.map +1 -0
  128. package/dist/render.js +20 -0
  129. package/dist/sanitizing-http-agent.d.ts +28 -0
  130. package/dist/sanitizing-http-agent.d.ts.map +1 -0
  131. package/dist/sanitizing-http-agent.js +51 -0
  132. package/dist/slack-listener.d.ts +73 -0
  133. package/dist/slack-listener.d.ts.map +1 -0
  134. package/dist/slack-listener.js +126 -0
  135. package/dist/slack-listener.test.d.ts +2 -0
  136. package/dist/slack-listener.test.d.ts.map +1 -0
  137. package/dist/slack-listener.test.js +115 -0
  138. package/dist/types.d.ts +153 -0
  139. package/dist/types.d.ts.map +1 -0
  140. package/dist/types.js +20 -0
  141. package/package.json +73 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download-files.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/download-files.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,142 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { buildFileContentParts } from "../download-files.js";
3
+ function fakeFetch(bodyByUrl) {
4
+ return vi.fn(async (url) => {
5
+ const e = bodyByUrl[url];
6
+ if (!e)
7
+ return { ok: false, status: 404 };
8
+ return {
9
+ ok: e.ok ?? true,
10
+ status: e.status ?? 200,
11
+ arrayBuffer: async () => (e.bytes ?? Buffer.from("")).buffer.slice((e.bytes ?? Buffer.from("")).byteOffset, (e.bytes ?? Buffer.from("")).byteOffset +
12
+ (e.bytes ?? Buffer.from("")).byteLength),
13
+ };
14
+ });
15
+ }
16
+ afterEach(() => vi.unstubAllGlobals());
17
+ const img = {
18
+ name: "shot.png",
19
+ mimetype: "image/png",
20
+ url_private: "https://files.slack.com/shot.png",
21
+ };
22
+ const csv = {
23
+ name: "data.csv",
24
+ mimetype: "text/csv",
25
+ url_private: "https://files.slack.com/data.csv",
26
+ };
27
+ describe("buildFileContentParts", () => {
28
+ it("turns an image into a base64 image part", async () => {
29
+ const bytes = Buffer.from([1, 2, 3, 4]);
30
+ vi.stubGlobal("fetch", fakeFetch({ [img.url_private]: { bytes } }));
31
+ const { parts, notes } = await buildFileContentParts([img], "xoxb-tok");
32
+ expect(notes).toEqual([]);
33
+ expect(parts).toHaveLength(1);
34
+ expect(parts[0]).toMatchObject({
35
+ type: "image",
36
+ source: {
37
+ type: "data",
38
+ mimeType: "image/png",
39
+ value: bytes.toString("base64"),
40
+ },
41
+ });
42
+ });
43
+ it("decodes a text/csv file into a text part", async () => {
44
+ const bytes = Buffer.from("a,b\n1,2\n", "utf8");
45
+ vi.stubGlobal("fetch", fakeFetch({ [csv.url_private]: { bytes } }));
46
+ const { parts } = await buildFileContentParts([csv], "tok");
47
+ expect(parts[0]?.type).toBe("text");
48
+ expect(parts[0].text).toContain("data.csv");
49
+ expect(parts[0].text).toContain("a,b");
50
+ });
51
+ it("truncates large text files", async () => {
52
+ const bytes = Buffer.from("x".repeat(5000), "utf8");
53
+ vi.stubGlobal("fetch", fakeFetch({ [csv.url_private]: { bytes } }));
54
+ const { parts } = await buildFileContentParts([csv], "tok", {
55
+ maxTextBytes: 100,
56
+ });
57
+ const text = parts[0].text;
58
+ expect(text).toContain("truncated");
59
+ expect(text.length).toBeLessThan(400);
60
+ });
61
+ it("turns a PDF into a document part", async () => {
62
+ const bytes = Buffer.from("%PDF-1.7 ...", "utf8");
63
+ const pdf = {
64
+ name: "report.pdf",
65
+ mimetype: "application/pdf",
66
+ url_private: "https://files.slack.com/report.pdf",
67
+ };
68
+ vi.stubGlobal("fetch", fakeFetch({ [pdf.url_private]: { bytes } }));
69
+ const { parts, notes } = await buildFileContentParts([pdf], "tok");
70
+ expect(notes).toEqual([]);
71
+ expect(parts[0]).toMatchObject({
72
+ type: "document",
73
+ source: {
74
+ type: "data",
75
+ mimeType: "application/pdf",
76
+ value: bytes.toString("base64"),
77
+ },
78
+ });
79
+ });
80
+ it.each([
81
+ { name: "memo.mp3", mimetype: "audio/mpeg", expected: "audio" },
82
+ { name: "clip.mp4", mimetype: "video/mp4", expected: "video" },
83
+ ])("passes $mimetype through as a $expected part", async ({ name, mimetype, expected }) => {
84
+ const bytes = Buffer.from([9, 8, 7, 6]);
85
+ const file = {
86
+ name,
87
+ mimetype,
88
+ url_private: `https://files.slack.com/${name}`,
89
+ };
90
+ vi.stubGlobal("fetch", fakeFetch({ [file.url_private]: { bytes } }));
91
+ const { parts, notes } = await buildFileContentParts([file], "tok");
92
+ expect(notes).toEqual([]);
93
+ expect(parts[0]).toMatchObject({
94
+ type: expected,
95
+ source: {
96
+ type: "data",
97
+ mimeType: mimetype,
98
+ value: bytes.toString("base64"),
99
+ },
100
+ });
101
+ });
102
+ it("skips genuinely unsupported types with a note", async () => {
103
+ const zip = {
104
+ name: "a.zip",
105
+ mimetype: "application/zip",
106
+ url_private: "u",
107
+ };
108
+ vi.stubGlobal("fetch", fakeFetch({}));
109
+ const { parts, notes } = await buildFileContentParts([zip], "tok");
110
+ expect(parts).toEqual([]);
111
+ expect(notes[0]).toContain("unsupported");
112
+ });
113
+ it("skips files over the size cap (by reported size) without downloading", async () => {
114
+ const big = { ...img, size: 99_999_999 };
115
+ const fetchSpy = fakeFetch({});
116
+ vi.stubGlobal("fetch", fetchSpy);
117
+ const { parts, notes } = await buildFileContentParts([big], "tok", {
118
+ maxBytesPerFile: 10,
119
+ });
120
+ expect(parts).toEqual([]);
121
+ expect(notes[0]).toContain("exceeds");
122
+ expect(fetchSpy).not.toHaveBeenCalled();
123
+ });
124
+ it("skips on a failed download with a note", async () => {
125
+ vi.stubGlobal("fetch", fakeFetch({ [img.url_private]: { ok: false, status: 403 } }));
126
+ const { parts, notes } = await buildFileContentParts([img], "tok");
127
+ expect(parts).toEqual([]);
128
+ expect(notes[0]).toContain("403");
129
+ });
130
+ it("caps the number of files processed", async () => {
131
+ const files = Array.from({ length: 8 }, (_, i) => ({
132
+ ...csv,
133
+ url_private: `u${i}`,
134
+ }));
135
+ vi.stubGlobal("fetch", fakeFetch(Object.fromEntries(files.map((f) => [f.url_private, { bytes: Buffer.from("x") }]))));
136
+ const { parts, notes } = await buildFileContentParts(files, "tok", {
137
+ maxFiles: 3,
138
+ });
139
+ expect(parts).toHaveLength(3);
140
+ expect(notes.some((n) => n.includes("first 3 of 8"))).toBe(true);
141
+ });
142
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ephemeral.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ephemeral.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/ephemeral.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,85 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { SlackAdapter } from "../adapter.js";
3
+ describe("SlackAdapter.postEphemeral", () => {
4
+ it("posts a native ephemeral message (usedFallback=false)", async () => {
5
+ const adapter = new SlackAdapter({
6
+ botToken: "xoxb",
7
+ appToken: "xapp",
8
+ signingSecret: "s",
9
+ });
10
+ const postEphemeral = vi
11
+ .fn()
12
+ .mockResolvedValue({ ok: true, message_ts: "5.5" });
13
+ // @ts-expect-error inject stub
14
+ adapter.client = { chat: { postEphemeral } };
15
+ const ir = [{ type: "text", props: { value: "hi" } }];
16
+ const res = await adapter.postEphemeral({ channel: "C1", threadTs: "1.0" }, { id: "U1" }, ir, { fallbackToDM: false });
17
+ expect(res).toMatchObject({ ok: true, usedFallback: false });
18
+ expect(postEphemeral).toHaveBeenCalledWith(expect.objectContaining({ channel: "C1", user: "U1", thread_ts: "1.0" }));
19
+ });
20
+ it("accepts a string user id", async () => {
21
+ const adapter = new SlackAdapter({
22
+ botToken: "xoxb",
23
+ appToken: "xapp",
24
+ signingSecret: "s",
25
+ });
26
+ const postEphemeral = vi
27
+ .fn()
28
+ .mockResolvedValue({ ok: true, message_ts: "6.0" });
29
+ // @ts-expect-error inject stub
30
+ adapter.client = { chat: { postEphemeral } };
31
+ const res = await adapter.postEphemeral({ channel: "C2" }, "U2", [], {
32
+ fallbackToDM: false,
33
+ });
34
+ expect(res).toMatchObject({ ok: true, usedFallback: false });
35
+ expect(postEphemeral).toHaveBeenCalledWith(expect.objectContaining({ channel: "C2", user: "U2" }));
36
+ // No thread_ts when target has none.
37
+ const args = postEphemeral.mock.calls[0][0];
38
+ expect(args["thread_ts"]).toBeUndefined();
39
+ });
40
+ it("omits thread_ts when target has none", async () => {
41
+ const adapter = new SlackAdapter({
42
+ botToken: "xoxb",
43
+ appToken: "xapp",
44
+ signingSecret: "s",
45
+ });
46
+ const postEphemeral = vi
47
+ .fn()
48
+ .mockResolvedValue({ ok: true, message_ts: "7.0" });
49
+ // @ts-expect-error inject stub
50
+ adapter.client = { chat: { postEphemeral } };
51
+ await adapter.postEphemeral({ channel: "C3" }, { id: "U3" }, [], {
52
+ fallbackToDM: false,
53
+ });
54
+ const args = postEphemeral.mock.calls[0][0];
55
+ expect(args["thread_ts"]).toBeUndefined();
56
+ });
57
+ it("ignores fallbackToDM and always posts natively (usedFallback always false)", async () => {
58
+ const adapter = new SlackAdapter({
59
+ botToken: "xoxb",
60
+ appToken: "xapp",
61
+ signingSecret: "s",
62
+ });
63
+ const postEphemeral = vi
64
+ .fn()
65
+ .mockResolvedValue({ ok: true, message_ts: "8.0" });
66
+ // @ts-expect-error inject stub
67
+ adapter.client = { chat: { postEphemeral } };
68
+ const res = await adapter.postEphemeral({ channel: "C4" }, { id: "U4" }, [], { fallbackToDM: true });
69
+ expect(res).toMatchObject({ ok: true, usedFallback: false });
70
+ });
71
+ it("returns { ok: false, error } when the Slack API throws", async () => {
72
+ const adapter = new SlackAdapter({
73
+ botToken: "xoxb",
74
+ appToken: "xapp",
75
+ signingSecret: "s",
76
+ });
77
+ const postEphemeral = vi
78
+ .fn()
79
+ .mockRejectedValue(new Error("channel_not_found"));
80
+ // @ts-expect-error inject stub
81
+ adapter.client = { chat: { postEphemeral } };
82
+ const res = await adapter.postEphemeral({ channel: "C5" }, { id: "U5" }, [], { fallbackToDM: false });
83
+ expect(res).toEqual({ ok: false, error: "channel_not_found" });
84
+ });
85
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=event-renderer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-renderer.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/event-renderer.test.ts"],"names":[],"mappings":""}