confused-ai-core 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 (114) hide show
  1. package/FEATURES.md +169 -0
  2. package/package.json +119 -0
  3. package/src/agent.ts +187 -0
  4. package/src/agentic/index.ts +87 -0
  5. package/src/agentic/runner.ts +386 -0
  6. package/src/agentic/types.ts +91 -0
  7. package/src/artifacts/artifact.ts +417 -0
  8. package/src/artifacts/index.ts +42 -0
  9. package/src/artifacts/media.ts +304 -0
  10. package/src/cli/index.ts +122 -0
  11. package/src/core/base-agent.ts +151 -0
  12. package/src/core/context-builder.ts +106 -0
  13. package/src/core/index.ts +8 -0
  14. package/src/core/schemas.ts +17 -0
  15. package/src/core/types.ts +158 -0
  16. package/src/create-agent.ts +309 -0
  17. package/src/debug-logger.ts +188 -0
  18. package/src/dx/agent.ts +88 -0
  19. package/src/dx/define-agent.ts +183 -0
  20. package/src/dx/dev-logger.ts +57 -0
  21. package/src/dx/index.ts +11 -0
  22. package/src/errors.ts +175 -0
  23. package/src/execution/engine.ts +522 -0
  24. package/src/execution/graph-builder.ts +362 -0
  25. package/src/execution/index.ts +8 -0
  26. package/src/execution/types.ts +257 -0
  27. package/src/execution/worker-pool.ts +308 -0
  28. package/src/extensions/index.ts +123 -0
  29. package/src/guardrails/allowlist.ts +155 -0
  30. package/src/guardrails/index.ts +17 -0
  31. package/src/guardrails/types.ts +159 -0
  32. package/src/guardrails/validator.ts +265 -0
  33. package/src/index.ts +74 -0
  34. package/src/knowledge/index.ts +5 -0
  35. package/src/knowledge/types.ts +52 -0
  36. package/src/learning/in-memory-store.ts +72 -0
  37. package/src/learning/index.ts +6 -0
  38. package/src/learning/types.ts +42 -0
  39. package/src/llm/cache.ts +300 -0
  40. package/src/llm/index.ts +22 -0
  41. package/src/llm/model-resolver.ts +81 -0
  42. package/src/llm/openai-provider.ts +313 -0
  43. package/src/llm/openrouter-provider.ts +29 -0
  44. package/src/llm/types.ts +131 -0
  45. package/src/memory/in-memory-store.ts +255 -0
  46. package/src/memory/index.ts +7 -0
  47. package/src/memory/types.ts +193 -0
  48. package/src/memory/vector-store.ts +251 -0
  49. package/src/observability/console-logger.ts +123 -0
  50. package/src/observability/index.ts +12 -0
  51. package/src/observability/metrics.ts +85 -0
  52. package/src/observability/otlp-exporter.ts +417 -0
  53. package/src/observability/tracer.ts +105 -0
  54. package/src/observability/types.ts +341 -0
  55. package/src/orchestration/agent-adapter.ts +33 -0
  56. package/src/orchestration/index.ts +34 -0
  57. package/src/orchestration/load-balancer.ts +151 -0
  58. package/src/orchestration/mcp-types.ts +59 -0
  59. package/src/orchestration/message-bus.ts +192 -0
  60. package/src/orchestration/orchestrator.ts +349 -0
  61. package/src/orchestration/pipeline.ts +66 -0
  62. package/src/orchestration/supervisor.ts +107 -0
  63. package/src/orchestration/swarm.ts +1099 -0
  64. package/src/orchestration/toolkit.ts +47 -0
  65. package/src/orchestration/types.ts +339 -0
  66. package/src/planner/classical-planner.ts +383 -0
  67. package/src/planner/index.ts +8 -0
  68. package/src/planner/llm-planner.ts +353 -0
  69. package/src/planner/types.ts +227 -0
  70. package/src/planner/validator.ts +297 -0
  71. package/src/production/circuit-breaker.ts +290 -0
  72. package/src/production/graceful-shutdown.ts +251 -0
  73. package/src/production/health.ts +333 -0
  74. package/src/production/index.ts +57 -0
  75. package/src/production/latency-eval.ts +62 -0
  76. package/src/production/rate-limiter.ts +287 -0
  77. package/src/production/resumable-stream.ts +289 -0
  78. package/src/production/types.ts +81 -0
  79. package/src/sdk/index.ts +374 -0
  80. package/src/session/db-driver.ts +50 -0
  81. package/src/session/in-memory-store.ts +235 -0
  82. package/src/session/index.ts +12 -0
  83. package/src/session/sql-store.ts +315 -0
  84. package/src/session/sqlite-store.ts +61 -0
  85. package/src/session/types.ts +153 -0
  86. package/src/tools/base-tool.ts +223 -0
  87. package/src/tools/browser-tool.ts +123 -0
  88. package/src/tools/calculator-tool.ts +265 -0
  89. package/src/tools/file-tools.ts +394 -0
  90. package/src/tools/github-tool.ts +432 -0
  91. package/src/tools/hackernews-tool.ts +187 -0
  92. package/src/tools/http-tool.ts +118 -0
  93. package/src/tools/index.ts +99 -0
  94. package/src/tools/jira-tool.ts +373 -0
  95. package/src/tools/notion-tool.ts +322 -0
  96. package/src/tools/openai-tool.ts +236 -0
  97. package/src/tools/registry.ts +131 -0
  98. package/src/tools/serpapi-tool.ts +234 -0
  99. package/src/tools/shell-tool.ts +118 -0
  100. package/src/tools/slack-tool.ts +327 -0
  101. package/src/tools/telegram-tool.ts +127 -0
  102. package/src/tools/types.ts +229 -0
  103. package/src/tools/websearch-tool.ts +335 -0
  104. package/src/tools/wikipedia-tool.ts +177 -0
  105. package/src/tools/yfinance-tool.ts +33 -0
  106. package/src/voice/index.ts +17 -0
  107. package/src/voice/voice-provider.ts +228 -0
  108. package/tests/artifact.test.ts +241 -0
  109. package/tests/circuit-breaker.test.ts +171 -0
  110. package/tests/health.test.ts +192 -0
  111. package/tests/llm-cache.test.ts +186 -0
  112. package/tests/rate-limiter.test.ts +161 -0
  113. package/tsconfig.json +29 -0
  114. package/vitest.config.ts +47 -0
@@ -0,0 +1,234 @@
1
+ /**
2
+ * SerpApi tool implementation - TypeScript SerpApiTools
3
+ */
4
+
5
+ import { z } from 'zod';
6
+ import { BaseTool, BaseToolConfig } from './base-tool.js';
7
+ import { ToolContext, ToolCategory } from './types.js';
8
+
9
+ /**
10
+ * SerpApi result types
11
+ */
12
+ interface SerpApiSearchResult {
13
+ title?: string;
14
+ link?: string;
15
+ snippet?: string;
16
+ displayed_link?: string;
17
+ }
18
+
19
+ interface SerpApiVideoResult {
20
+ title?: string;
21
+ link?: string;
22
+ snippet?: string;
23
+ thumbnail?: string;
24
+ duration?: string;
25
+ }
26
+
27
+ interface SerpApiChannelResult {
28
+ title?: string;
29
+ link?: string;
30
+ thumbnail?: string;
31
+ }
32
+
33
+ interface SerpApiResult {
34
+ data?: unknown;
35
+ error?: string;
36
+ }
37
+
38
+ /**
39
+ * Base SerpApi tool with common authentication
40
+ */
41
+ abstract class BaseSerpApiTool<TParams extends z.ZodObject<Record<string, z.ZodType>>> extends BaseTool<TParams, SerpApiResult> {
42
+ protected apiKey: string;
43
+ protected baseUrl = 'https://serpapi.com/search';
44
+
45
+ constructor(
46
+ config: Partial<Omit<BaseToolConfig<TParams>, 'parameters'>> & {
47
+ apiKey?: string;
48
+ },
49
+ params: TParams
50
+ ) {
51
+ super({
52
+ name: config.name || 'serpapi.tool',
53
+ description: config.description || 'SerpApi tool',
54
+ parameters: params,
55
+ category: config.category || ToolCategory.WEB,
56
+ permissions: {
57
+ allowNetwork: true,
58
+ maxExecutionTimeMs: 30000,
59
+ ...config.permissions,
60
+ },
61
+ ...config,
62
+ });
63
+
64
+ this.apiKey = config.apiKey || process.env.SERPAPI_API_KEY || '';
65
+
66
+ if (!this.apiKey) {
67
+ throw new Error('SerpApi API key is required. Set SERPAPI_API_KEY environment variable or pass apiKey in config.');
68
+ }
69
+ }
70
+
71
+ protected async serpApiRequest(params: Record<string, string>): Promise<Response> {
72
+ const queryParams = new URLSearchParams({
73
+ api_key: this.apiKey,
74
+ ...params,
75
+ });
76
+
77
+ return fetch(`${this.baseUrl}?${queryParams.toString()}`);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Google search tool
83
+ */
84
+ const SerpApiGoogleSearchParameters = z.object({
85
+ query: z.string().describe('The search query'),
86
+ num_results: z.number().min(1).max(100).optional().default(10).describe('Number of results to return'),
87
+ });
88
+
89
+ export class SerpApiGoogleSearchTool extends BaseSerpApiTool<typeof SerpApiGoogleSearchParameters> {
90
+ constructor(
91
+ config?: Partial<Omit<BaseToolConfig<typeof SerpApiGoogleSearchParameters>, 'parameters'>> & {
92
+ apiKey?: string;
93
+ }
94
+ ) {
95
+ super(
96
+ {
97
+ name: config?.name ?? 'serpapi.google_search',
98
+ description: config?.description ?? 'Search Google using SerpApi',
99
+ ...config,
100
+ },
101
+ SerpApiGoogleSearchParameters
102
+ );
103
+ }
104
+
105
+ protected async performExecute(
106
+ params: z.infer<typeof SerpApiGoogleSearchParameters>,
107
+ _context: ToolContext
108
+ ): Promise<SerpApiResult> {
109
+ try {
110
+ const response = await this.serpApiRequest({
111
+ engine: 'google',
112
+ q: params.query,
113
+ num: params.num_results.toString(),
114
+ });
115
+
116
+ if (!response.ok) {
117
+ throw new Error(`SerpApi error: ${response.status}`);
118
+ }
119
+
120
+ const data = (await response.json()) as {
121
+ organic_results?: SerpApiSearchResult[];
122
+ knowledge_graph?: unknown;
123
+ related_questions?: unknown[];
124
+ };
125
+
126
+ return {
127
+ data: {
128
+ search_results: (data.organic_results || []).map((result) => ({
129
+ title: result.title,
130
+ url: result.link,
131
+ snippet: result.snippet,
132
+ displayed_link: result.displayed_link,
133
+ })),
134
+ knowledge_graph: data.knowledge_graph,
135
+ related_questions: data.related_questions,
136
+ },
137
+ };
138
+ } catch (error) {
139
+ return {
140
+ error: error instanceof Error ? error.message : 'Unknown error occurred',
141
+ };
142
+ }
143
+ }
144
+ }
145
+
146
+ /**
147
+ * YouTube search tool
148
+ */
149
+ const SerpApiYouTubeSearchParameters = z.object({
150
+ query: z.string().describe('The search query'),
151
+ num_results: z.number().min(1).max(50).optional().default(10).describe('Number of results to return'),
152
+ });
153
+
154
+ export class SerpApiYouTubeSearchTool extends BaseSerpApiTool<typeof SerpApiYouTubeSearchParameters> {
155
+ constructor(
156
+ config?: Partial<Omit<BaseToolConfig<typeof SerpApiYouTubeSearchParameters>, 'parameters'>> & {
157
+ apiKey?: string;
158
+ }
159
+ ) {
160
+ super(
161
+ {
162
+ name: config?.name ?? 'serpapi.youtube_search',
163
+ description: config?.description ?? 'Search YouTube using SerpApi',
164
+ ...config,
165
+ },
166
+ SerpApiYouTubeSearchParameters
167
+ );
168
+ }
169
+
170
+ protected async performExecute(
171
+ params: z.infer<typeof SerpApiYouTubeSearchParameters>,
172
+ _context: ToolContext
173
+ ): Promise<SerpApiResult> {
174
+ try {
175
+ const response = await this.serpApiRequest({
176
+ engine: 'youtube',
177
+ search_query: params.query,
178
+ num: params.num_results.toString(),
179
+ });
180
+
181
+ if (!response.ok) {
182
+ throw new Error(`SerpApi error: ${response.status}`);
183
+ }
184
+
185
+ const data = (await response.json()) as {
186
+ video_results?: SerpApiVideoResult[];
187
+ channel_results?: SerpApiChannelResult[];
188
+ };
189
+
190
+ return {
191
+ data: {
192
+ video_results: (data.video_results || []).map((result) => ({
193
+ title: result.title,
194
+ url: result.link,
195
+ snippet: result.snippet,
196
+ thumbnail: result.thumbnail,
197
+ duration: result.duration,
198
+ })),
199
+ channel_results: (data.channel_results || []).map((result) => ({
200
+ title: result.title,
201
+ url: result.link,
202
+ thumbnail: result.thumbnail,
203
+ })),
204
+ },
205
+ };
206
+ } catch (error) {
207
+ return {
208
+ error: error instanceof Error ? error.message : 'Unknown error occurred',
209
+ };
210
+ }
211
+ }
212
+ }
213
+
214
+ /**
215
+ * SerpApi toolkit
216
+ */
217
+ export class SerpApiToolkit {
218
+ static create(options?: {
219
+ apiKey?: string;
220
+ enableGoogleSearch?: boolean;
221
+ enableYouTubeSearch?: boolean;
222
+ }): Array<SerpApiGoogleSearchTool | SerpApiYouTubeSearchTool> {
223
+ const tools: Array<SerpApiGoogleSearchTool | SerpApiYouTubeSearchTool> = [];
224
+
225
+ if (options?.enableGoogleSearch !== false) {
226
+ tools.push(new SerpApiGoogleSearchTool({ apiKey: options?.apiKey }));
227
+ }
228
+ if (options?.enableYouTubeSearch !== false) {
229
+ tools.push(new SerpApiYouTubeSearchTool({ apiKey: options?.apiKey }));
230
+ }
231
+
232
+ return tools;
233
+ }
234
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Shell tool implementation - TypeScript ShellTools
3
+ */
4
+
5
+ import { z } from 'zod';
6
+ import { BaseTool, BaseToolConfig } from './base-tool.js';
7
+ import { ToolContext, ToolCategory } from './types.js';
8
+ import { exec } from 'child_process';
9
+ import { promisify } from 'util';
10
+ import * as path from 'path';
11
+
12
+ const execAsync = promisify(exec);
13
+
14
+ /**
15
+ * Shell command result
16
+ */
17
+ interface ShellResult {
18
+ stdout: string;
19
+ stderr: string;
20
+ exitCode: number;
21
+ error?: string;
22
+ }
23
+
24
+ /**
25
+ * Parameters for shell command execution
26
+ */
27
+ const ShellCommandParameters = z.object({
28
+ command: z.string().describe('The shell command to execute'),
29
+ cwd: z.string().optional().describe('Working directory for the command (optional)'),
30
+ timeout: z.number().min(1000).max(300000).optional().default(30000).describe('Timeout in milliseconds'),
31
+ });
32
+
33
+ /**
34
+ * Shell tool for running shell commands
35
+ */
36
+ export class ShellTool extends BaseTool<typeof ShellCommandParameters, ShellResult> {
37
+ private baseDir?: string;
38
+
39
+ constructor(
40
+ config?: Partial<Omit<BaseToolConfig<typeof ShellCommandParameters>, 'parameters'>> & {
41
+ baseDir?: string;
42
+ }
43
+ ) {
44
+ super({
45
+ name: config?.name ?? 'shell.run',
46
+ description: config?.description ?? 'Run a shell command and return the output',
47
+ parameters: ShellCommandParameters,
48
+ category: config?.category ?? ToolCategory.UTILITY,
49
+ permissions: {
50
+ allowNetwork: false,
51
+ allowFileSystem: true,
52
+ maxExecutionTimeMs: 30000,
53
+ ...config?.permissions,
54
+ },
55
+ ...config,
56
+ });
57
+ this.baseDir = config?.baseDir;
58
+ }
59
+
60
+ protected async performExecute(
61
+ params: z.infer<typeof ShellCommandParameters>,
62
+ _context: ToolContext
63
+ ): Promise<ShellResult> {
64
+ const cwd = params.cwd || this.baseDir || process.cwd();
65
+
66
+ // Validate the working directory is safe
67
+ const resolvedCwd = path.resolve(cwd);
68
+ const resolvedBase = this.baseDir ? path.resolve(this.baseDir) : resolvedCwd;
69
+
70
+ if (this.baseDir && !resolvedCwd.startsWith(resolvedBase)) {
71
+ return {
72
+ stdout: '',
73
+ stderr: '',
74
+ exitCode: 1,
75
+ error: `Working directory ${cwd} is outside the allowed base directory`,
76
+ };
77
+ }
78
+
79
+ try {
80
+ const { stdout, stderr } = await execAsync(params.command, {
81
+ cwd: resolvedCwd,
82
+ timeout: params.timeout,
83
+ maxBuffer: 1024 * 1024, // 1MB buffer
84
+ });
85
+
86
+ return {
87
+ stdout: stdout.trim(),
88
+ stderr: stderr.trim(),
89
+ exitCode: 0,
90
+ };
91
+ } catch (error) {
92
+ if (error instanceof Error && 'stdout' in error && 'stderr' in error) {
93
+ const execError = error as unknown as { stdout: string; stderr: string; code?: number };
94
+ return {
95
+ stdout: execError.stdout?.trim() || '',
96
+ stderr: execError.stderr?.trim() || '',
97
+ exitCode: execError.code ?? 1,
98
+ };
99
+ }
100
+
101
+ return {
102
+ stdout: '',
103
+ stderr: '',
104
+ exitCode: 1,
105
+ error: error instanceof Error ? error.message : 'Unknown error occurred',
106
+ };
107
+ }
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Shell toolkit
113
+ */
114
+ export class ShellToolkit {
115
+ static create(options?: { baseDir?: string }): Array<ShellTool> {
116
+ return [new ShellTool({ baseDir: options?.baseDir })];
117
+ }
118
+ }
@@ -0,0 +1,327 @@
1
+ /**
2
+ * Slack tool implementation - TypeScript SlackTools
3
+ */
4
+
5
+ import { z } from 'zod';
6
+ import { BaseTool, BaseToolConfig } from './base-tool.js';
7
+ import { ToolContext, ToolCategory } from './types.js';
8
+
9
+ /**
10
+ * Slack API response types
11
+ */
12
+ interface SlackPostMessageResponse {
13
+ ok: boolean;
14
+ channel?: string;
15
+ ts?: string;
16
+ message?: unknown;
17
+ error?: string;
18
+ }
19
+
20
+ interface SlackChannel {
21
+ id: string;
22
+ name: string;
23
+ }
24
+
25
+ interface SlackChannelsResponse {
26
+ ok: boolean;
27
+ channels?: SlackChannel[];
28
+ error?: string;
29
+ }
30
+
31
+ interface SlackMessage {
32
+ text?: string;
33
+ user?: string;
34
+ ts?: string;
35
+ subtype?: string;
36
+ bot_id?: string;
37
+ attachments?: unknown[];
38
+ }
39
+
40
+ interface SlackHistoryResponse {
41
+ ok: boolean;
42
+ messages?: SlackMessage[];
43
+ error?: string;
44
+ }
45
+
46
+ interface SlackResult {
47
+ success: boolean;
48
+ data?: unknown;
49
+ error?: string;
50
+ }
51
+
52
+ /**
53
+ * Parameters for sending a Slack message
54
+ */
55
+ const SlackSendMessageParameters = z.object({
56
+ channel: z.string().describe('The channel ID or name to send the message to'),
57
+ text: z.string().describe('The text of the message to send'),
58
+ thread_ts: z.string().optional().describe('Timestamp of the parent message (for threaded replies)'),
59
+ });
60
+
61
+ /**
62
+ * Slack send message tool
63
+ */
64
+ export class SlackSendMessageTool extends BaseTool<typeof SlackSendMessageParameters, SlackResult> {
65
+ private token: string;
66
+ private baseUrl = 'https://slack.com/api';
67
+
68
+ constructor(
69
+ config?: Partial<Omit<BaseToolConfig<typeof SlackSendMessageParameters>, 'parameters'>> & {
70
+ token?: string;
71
+ }
72
+ ) {
73
+ super({
74
+ name: config?.name ?? 'slack.send_message',
75
+ description: config?.description ?? 'Send a message to a Slack channel',
76
+ parameters: SlackSendMessageParameters,
77
+ category: config?.category ?? ToolCategory.API,
78
+ permissions: {
79
+ allowNetwork: true,
80
+ maxExecutionTimeMs: 30000,
81
+ ...config?.permissions,
82
+ },
83
+ ...config,
84
+ });
85
+
86
+ this.token = config?.token || process.env.SLACK_TOKEN || '';
87
+
88
+ if (!this.token) {
89
+ throw new Error('Slack token is required. Set SLACK_TOKEN environment variable or pass token in config.');
90
+ }
91
+ }
92
+
93
+ protected async performExecute(
94
+ params: z.infer<typeof SlackSendMessageParameters>,
95
+ _context: ToolContext
96
+ ): Promise<SlackResult> {
97
+ try {
98
+ const body: Record<string, string> = {
99
+ channel: params.channel,
100
+ text: params.text,
101
+ };
102
+
103
+ if (params.thread_ts) {
104
+ body.thread_ts = params.thread_ts;
105
+ }
106
+
107
+ const response = await fetch(`${this.baseUrl}/chat.postMessage`, {
108
+ method: 'POST',
109
+ headers: {
110
+ Authorization: `Bearer ${this.token}`,
111
+ 'Content-Type': 'application/json',
112
+ },
113
+ body: JSON.stringify(body),
114
+ });
115
+
116
+ const data = (await response.json()) as SlackPostMessageResponse;
117
+
118
+ if (data.ok) {
119
+ return {
120
+ success: true,
121
+ data: {
122
+ channel: data.channel,
123
+ ts: data.ts,
124
+ message: data.message,
125
+ },
126
+ };
127
+ } else {
128
+ return {
129
+ success: false,
130
+ error: data.error || 'Unknown Slack API error',
131
+ };
132
+ }
133
+ } catch (error) {
134
+ return {
135
+ success: false,
136
+ error: error instanceof Error ? error.message : 'Unknown error occurred',
137
+ };
138
+ }
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Parameters for listing Slack channels
144
+ */
145
+ const SlackListChannelsParameters = z.object({
146
+ limit: z.number().min(1).max(200).optional().default(100).describe('Maximum number of channels to return'),
147
+ });
148
+
149
+ /**
150
+ * Slack list channels tool
151
+ */
152
+ export class SlackListChannelsTool extends BaseTool<typeof SlackListChannelsParameters, SlackResult> {
153
+ private token: string;
154
+ private baseUrl = 'https://slack.com/api';
155
+
156
+ constructor(
157
+ config?: Partial<Omit<BaseToolConfig<typeof SlackListChannelsParameters>, 'parameters'>> & {
158
+ token?: string;
159
+ }
160
+ ) {
161
+ super({
162
+ name: config?.name ?? 'slack.list_channels',
163
+ description: config?.description ?? 'List all channels in the Slack workspace',
164
+ parameters: SlackListChannelsParameters,
165
+ category: config?.category ?? ToolCategory.API,
166
+ permissions: {
167
+ allowNetwork: true,
168
+ maxExecutionTimeMs: 30000,
169
+ ...config?.permissions,
170
+ },
171
+ ...config,
172
+ });
173
+
174
+ this.token = config?.token || process.env.SLACK_TOKEN || '';
175
+
176
+ if (!this.token) {
177
+ throw new Error('Slack token is required. Set SLACK_TOKEN environment variable or pass token in config.');
178
+ }
179
+ }
180
+
181
+ protected async performExecute(
182
+ params: z.infer<typeof SlackListChannelsParameters>,
183
+ _context: ToolContext
184
+ ): Promise<SlackResult> {
185
+ try {
186
+ const response = await fetch(`${this.baseUrl}/conversations.list?limit=${params.limit}`, {
187
+ headers: {
188
+ Authorization: `Bearer ${this.token}`,
189
+ },
190
+ });
191
+
192
+ const data = (await response.json()) as SlackChannelsResponse;
193
+
194
+ if (data.ok) {
195
+ const channels = (data.channels || []).map((channel) => ({
196
+ id: channel.id,
197
+ name: channel.name,
198
+ }));
199
+
200
+ return {
201
+ success: true,
202
+ data: channels,
203
+ };
204
+ } else {
205
+ return {
206
+ success: false,
207
+ error: data.error || 'Unknown Slack API error',
208
+ };
209
+ }
210
+ } catch (error) {
211
+ return {
212
+ success: false,
213
+ error: error instanceof Error ? error.message : 'Unknown error occurred',
214
+ };
215
+ }
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Parameters for getting channel history
221
+ */
222
+ const SlackGetChannelHistoryParameters = z.object({
223
+ channel: z.string().describe('The channel ID to fetch history from'),
224
+ limit: z.number().min(1).max(200).optional().default(100).describe('Maximum number of messages to return'),
225
+ });
226
+
227
+ /**
228
+ * Slack get channel history tool
229
+ */
230
+ export class SlackGetChannelHistoryTool extends BaseTool<typeof SlackGetChannelHistoryParameters, SlackResult> {
231
+ private token: string;
232
+ private baseUrl = 'https://slack.com/api';
233
+
234
+ constructor(
235
+ config?: Partial<Omit<BaseToolConfig<typeof SlackGetChannelHistoryParameters>, 'parameters'>> & {
236
+ token?: string;
237
+ }
238
+ ) {
239
+ super({
240
+ name: config?.name ?? 'slack.get_channel_history',
241
+ description: config?.description ?? 'Get the message history of a Slack channel',
242
+ parameters: SlackGetChannelHistoryParameters,
243
+ category: config?.category ?? ToolCategory.API,
244
+ permissions: {
245
+ allowNetwork: true,
246
+ maxExecutionTimeMs: 30000,
247
+ ...config?.permissions,
248
+ },
249
+ ...config,
250
+ });
251
+
252
+ this.token = config?.token || process.env.SLACK_TOKEN || '';
253
+
254
+ if (!this.token) {
255
+ throw new Error('Slack token is required. Set SLACK_TOKEN environment variable or pass token in config.');
256
+ }
257
+ }
258
+
259
+ protected async performExecute(
260
+ params: z.infer<typeof SlackGetChannelHistoryParameters>,
261
+ _context: ToolContext
262
+ ): Promise<SlackResult> {
263
+ try {
264
+ const response = await fetch(
265
+ `${this.baseUrl}/conversations.history?channel=${encodeURIComponent(params.channel)}&limit=${params.limit}`,
266
+ {
267
+ headers: {
268
+ Authorization: `Bearer ${this.token}`,
269
+ },
270
+ }
271
+ );
272
+
273
+ const data = (await response.json()) as SlackHistoryResponse;
274
+
275
+ if (data.ok) {
276
+ const messages = (data.messages || []).map((msg) => ({
277
+ text: msg.text,
278
+ user: msg.user || (msg.bot_id ? 'bot' : 'unknown'),
279
+ ts: msg.ts,
280
+ subtype: msg.subtype || 'normal',
281
+ attachments: msg.attachments,
282
+ }));
283
+
284
+ return {
285
+ success: true,
286
+ data: messages,
287
+ };
288
+ } else {
289
+ return {
290
+ success: false,
291
+ error: data.error || 'Unknown Slack API error',
292
+ };
293
+ }
294
+ } catch (error) {
295
+ return {
296
+ success: false,
297
+ error: error instanceof Error ? error.message : 'Unknown error occurred',
298
+ };
299
+ }
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Slack toolkit
305
+ */
306
+ export class SlackToolkit {
307
+ static create(options?: {
308
+ token?: string;
309
+ enableSendMessage?: boolean;
310
+ enableListChannels?: boolean;
311
+ enableGetHistory?: boolean;
312
+ }): Array<SlackSendMessageTool | SlackListChannelsTool | SlackGetChannelHistoryTool> {
313
+ const tools: Array<SlackSendMessageTool | SlackListChannelsTool | SlackGetChannelHistoryTool> = [];
314
+
315
+ if (options?.enableSendMessage !== false) {
316
+ tools.push(new SlackSendMessageTool({ token: options?.token }));
317
+ }
318
+ if (options?.enableListChannels !== false) {
319
+ tools.push(new SlackListChannelsTool({ token: options?.token }));
320
+ }
321
+ if (options?.enableGetHistory !== false) {
322
+ tools.push(new SlackGetChannelHistoryTool({ token: options?.token }));
323
+ }
324
+
325
+ return tools;
326
+ }
327
+ }