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.
- package/FEATURES.md +169 -0
- package/package.json +119 -0
- package/src/agent.ts +187 -0
- package/src/agentic/index.ts +87 -0
- package/src/agentic/runner.ts +386 -0
- package/src/agentic/types.ts +91 -0
- package/src/artifacts/artifact.ts +417 -0
- package/src/artifacts/index.ts +42 -0
- package/src/artifacts/media.ts +304 -0
- package/src/cli/index.ts +122 -0
- package/src/core/base-agent.ts +151 -0
- package/src/core/context-builder.ts +106 -0
- package/src/core/index.ts +8 -0
- package/src/core/schemas.ts +17 -0
- package/src/core/types.ts +158 -0
- package/src/create-agent.ts +309 -0
- package/src/debug-logger.ts +188 -0
- package/src/dx/agent.ts +88 -0
- package/src/dx/define-agent.ts +183 -0
- package/src/dx/dev-logger.ts +57 -0
- package/src/dx/index.ts +11 -0
- package/src/errors.ts +175 -0
- package/src/execution/engine.ts +522 -0
- package/src/execution/graph-builder.ts +362 -0
- package/src/execution/index.ts +8 -0
- package/src/execution/types.ts +257 -0
- package/src/execution/worker-pool.ts +308 -0
- package/src/extensions/index.ts +123 -0
- package/src/guardrails/allowlist.ts +155 -0
- package/src/guardrails/index.ts +17 -0
- package/src/guardrails/types.ts +159 -0
- package/src/guardrails/validator.ts +265 -0
- package/src/index.ts +74 -0
- package/src/knowledge/index.ts +5 -0
- package/src/knowledge/types.ts +52 -0
- package/src/learning/in-memory-store.ts +72 -0
- package/src/learning/index.ts +6 -0
- package/src/learning/types.ts +42 -0
- package/src/llm/cache.ts +300 -0
- package/src/llm/index.ts +22 -0
- package/src/llm/model-resolver.ts +81 -0
- package/src/llm/openai-provider.ts +313 -0
- package/src/llm/openrouter-provider.ts +29 -0
- package/src/llm/types.ts +131 -0
- package/src/memory/in-memory-store.ts +255 -0
- package/src/memory/index.ts +7 -0
- package/src/memory/types.ts +193 -0
- package/src/memory/vector-store.ts +251 -0
- package/src/observability/console-logger.ts +123 -0
- package/src/observability/index.ts +12 -0
- package/src/observability/metrics.ts +85 -0
- package/src/observability/otlp-exporter.ts +417 -0
- package/src/observability/tracer.ts +105 -0
- package/src/observability/types.ts +341 -0
- package/src/orchestration/agent-adapter.ts +33 -0
- package/src/orchestration/index.ts +34 -0
- package/src/orchestration/load-balancer.ts +151 -0
- package/src/orchestration/mcp-types.ts +59 -0
- package/src/orchestration/message-bus.ts +192 -0
- package/src/orchestration/orchestrator.ts +349 -0
- package/src/orchestration/pipeline.ts +66 -0
- package/src/orchestration/supervisor.ts +107 -0
- package/src/orchestration/swarm.ts +1099 -0
- package/src/orchestration/toolkit.ts +47 -0
- package/src/orchestration/types.ts +339 -0
- package/src/planner/classical-planner.ts +383 -0
- package/src/planner/index.ts +8 -0
- package/src/planner/llm-planner.ts +353 -0
- package/src/planner/types.ts +227 -0
- package/src/planner/validator.ts +297 -0
- package/src/production/circuit-breaker.ts +290 -0
- package/src/production/graceful-shutdown.ts +251 -0
- package/src/production/health.ts +333 -0
- package/src/production/index.ts +57 -0
- package/src/production/latency-eval.ts +62 -0
- package/src/production/rate-limiter.ts +287 -0
- package/src/production/resumable-stream.ts +289 -0
- package/src/production/types.ts +81 -0
- package/src/sdk/index.ts +374 -0
- package/src/session/db-driver.ts +50 -0
- package/src/session/in-memory-store.ts +235 -0
- package/src/session/index.ts +12 -0
- package/src/session/sql-store.ts +315 -0
- package/src/session/sqlite-store.ts +61 -0
- package/src/session/types.ts +153 -0
- package/src/tools/base-tool.ts +223 -0
- package/src/tools/browser-tool.ts +123 -0
- package/src/tools/calculator-tool.ts +265 -0
- package/src/tools/file-tools.ts +394 -0
- package/src/tools/github-tool.ts +432 -0
- package/src/tools/hackernews-tool.ts +187 -0
- package/src/tools/http-tool.ts +118 -0
- package/src/tools/index.ts +99 -0
- package/src/tools/jira-tool.ts +373 -0
- package/src/tools/notion-tool.ts +322 -0
- package/src/tools/openai-tool.ts +236 -0
- package/src/tools/registry.ts +131 -0
- package/src/tools/serpapi-tool.ts +234 -0
- package/src/tools/shell-tool.ts +118 -0
- package/src/tools/slack-tool.ts +327 -0
- package/src/tools/telegram-tool.ts +127 -0
- package/src/tools/types.ts +229 -0
- package/src/tools/websearch-tool.ts +335 -0
- package/src/tools/wikipedia-tool.ts +177 -0
- package/src/tools/yfinance-tool.ts +33 -0
- package/src/voice/index.ts +17 -0
- package/src/voice/voice-provider.ts +228 -0
- package/tests/artifact.test.ts +241 -0
- package/tests/circuit-breaker.test.ts +171 -0
- package/tests/health.test.ts +192 -0
- package/tests/llm-cache.test.ts +186 -0
- package/tests/rate-limiter.test.ts +161 -0
- package/tsconfig.json +29 -0
- package/vitest.config.ts +47 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client tool implementation
|
|
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
|
+
* HTTP methods
|
|
11
|
+
*/
|
|
12
|
+
const HttpMethod = z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']);
|
|
13
|
+
type HttpMethod = z.infer<typeof HttpMethod>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parameters for HTTP tool
|
|
17
|
+
*/
|
|
18
|
+
const HttpToolParameters = z.object({
|
|
19
|
+
url: z.string().url(),
|
|
20
|
+
method: HttpMethod.default('GET'),
|
|
21
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
22
|
+
body: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
|
|
23
|
+
timeout: z.number().min(1000).max(60000).optional(),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* HTTP response
|
|
28
|
+
*/
|
|
29
|
+
interface HttpResponse {
|
|
30
|
+
status: number;
|
|
31
|
+
statusText: string;
|
|
32
|
+
headers: Record<string, string>;
|
|
33
|
+
body: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* HTTP client tool for making web requests
|
|
38
|
+
*/
|
|
39
|
+
export class HttpClientTool extends BaseTool<typeof HttpToolParameters, HttpResponse> {
|
|
40
|
+
constructor(config?: Partial<Omit<BaseToolConfig<typeof HttpToolParameters>, 'parameters'>>) {
|
|
41
|
+
super({
|
|
42
|
+
name: config?.name ?? 'http.request',
|
|
43
|
+
description: config?.description ?? 'Make HTTP requests to external APIs and websites',
|
|
44
|
+
parameters: HttpToolParameters,
|
|
45
|
+
category: config?.category ?? ToolCategory.WEB,
|
|
46
|
+
permissions: {
|
|
47
|
+
allowNetwork: true,
|
|
48
|
+
maxExecutionTimeMs: 30000,
|
|
49
|
+
...config?.permissions,
|
|
50
|
+
},
|
|
51
|
+
version: config?.version,
|
|
52
|
+
author: config?.author,
|
|
53
|
+
tags: config?.tags,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Execute HTTP request
|
|
59
|
+
*/
|
|
60
|
+
protected async performExecute(
|
|
61
|
+
params: z.infer<typeof HttpToolParameters>,
|
|
62
|
+
_context: ToolContext
|
|
63
|
+
): Promise<HttpResponse> {
|
|
64
|
+
const { url, method, headers, body, timeout } = params;
|
|
65
|
+
|
|
66
|
+
const fetchOptions: RequestInit = {
|
|
67
|
+
method,
|
|
68
|
+
headers: {
|
|
69
|
+
'Accept': 'application/json, text/plain, */*',
|
|
70
|
+
'User-Agent': 'AgentFramework/1.0',
|
|
71
|
+
...headers,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
if (body && method !== 'GET' && method !== 'HEAD') {
|
|
76
|
+
if (typeof body === 'string') {
|
|
77
|
+
fetchOptions.body = body;
|
|
78
|
+
} else {
|
|
79
|
+
fetchOptions.body = JSON.stringify(body);
|
|
80
|
+
fetchOptions.headers = {
|
|
81
|
+
...fetchOptions.headers,
|
|
82
|
+
'Content-Type': 'application/json',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const controller = new AbortController();
|
|
88
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout ?? 30000);
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const response = await fetch(url, {
|
|
92
|
+
...fetchOptions,
|
|
93
|
+
signal: controller.signal,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
clearTimeout(timeoutId);
|
|
97
|
+
|
|
98
|
+
// Convert headers
|
|
99
|
+
const responseHeaders: Record<string, string> = {};
|
|
100
|
+
response.headers.forEach((value, key) => {
|
|
101
|
+
responseHeaders[key] = value;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Get response body
|
|
105
|
+
const responseBody = await response.text();
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
status: response.status,
|
|
109
|
+
statusText: response.statusText,
|
|
110
|
+
headers: responseHeaders,
|
|
111
|
+
body: responseBody,
|
|
112
|
+
};
|
|
113
|
+
} catch (error) {
|
|
114
|
+
clearTimeout(timeoutId);
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tools module exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Core types and base classes
|
|
6
|
+
export * from './types.js';
|
|
7
|
+
export { ToolRegistryImpl, toToolRegistry, type ToolProvider } from './registry.js';
|
|
8
|
+
export { BaseTool, type BaseToolConfig } from './base-tool.js';
|
|
9
|
+
|
|
10
|
+
// Core tools
|
|
11
|
+
export { HttpClientTool } from './http-tool.js';
|
|
12
|
+
export { BrowserTool } from './browser-tool.js';
|
|
13
|
+
export * from './file-tools.js';
|
|
14
|
+
|
|
15
|
+
// Calculator tools
|
|
16
|
+
export {
|
|
17
|
+
CalculatorAddTool,
|
|
18
|
+
CalculatorSubtractTool,
|
|
19
|
+
CalculatorMultiplyTool,
|
|
20
|
+
CalculatorDivideTool,
|
|
21
|
+
CalculatorExponentiateTool,
|
|
22
|
+
CalculatorFactorialTool,
|
|
23
|
+
CalculatorIsPrimeTool,
|
|
24
|
+
CalculatorSquareRootTool,
|
|
25
|
+
CalculatorToolkit,
|
|
26
|
+
} from './calculator-tool.js';
|
|
27
|
+
|
|
28
|
+
// Web search tools
|
|
29
|
+
export {
|
|
30
|
+
DuckDuckGoSearchTool,
|
|
31
|
+
DuckDuckGoNewsTool,
|
|
32
|
+
WebSearchTool,
|
|
33
|
+
WebSearchToolkit,
|
|
34
|
+
} from './websearch-tool.js';
|
|
35
|
+
|
|
36
|
+
// Wikipedia tools
|
|
37
|
+
export { WikipediaSearchTool, WikipediaToolkit } from './wikipedia-tool.js';
|
|
38
|
+
|
|
39
|
+
// Shell tools
|
|
40
|
+
export { ShellTool, ShellToolkit } from './shell-tool.js';
|
|
41
|
+
|
|
42
|
+
// HackerNews tools
|
|
43
|
+
export {
|
|
44
|
+
HackerNewsTopStoriesTool,
|
|
45
|
+
HackerNewsUserTool,
|
|
46
|
+
HackerNewsToolkit,
|
|
47
|
+
} from './hackernews-tool.js';
|
|
48
|
+
|
|
49
|
+
// Telegram tools
|
|
50
|
+
export { TelegramTool, TelegramToolkit } from './telegram-tool.js';
|
|
51
|
+
|
|
52
|
+
// GitHub tools
|
|
53
|
+
export {
|
|
54
|
+
GitHubSearchRepositoriesTool,
|
|
55
|
+
GitHubGetRepositoryTool,
|
|
56
|
+
GitHubListIssuesTool,
|
|
57
|
+
GitHubCreateIssueTool,
|
|
58
|
+
GitHubListPullRequestsTool,
|
|
59
|
+
GitHubToolkit,
|
|
60
|
+
} from './github-tool.js';
|
|
61
|
+
|
|
62
|
+
// Slack tools
|
|
63
|
+
export {
|
|
64
|
+
SlackSendMessageTool,
|
|
65
|
+
SlackListChannelsTool,
|
|
66
|
+
SlackGetChannelHistoryTool,
|
|
67
|
+
SlackToolkit,
|
|
68
|
+
} from './slack-tool.js';
|
|
69
|
+
|
|
70
|
+
// Jira tools
|
|
71
|
+
export {
|
|
72
|
+
JiraGetIssueTool,
|
|
73
|
+
JiraCreateIssueTool,
|
|
74
|
+
JiraSearchIssuesTool,
|
|
75
|
+
JiraAddCommentTool,
|
|
76
|
+
JiraToolkit,
|
|
77
|
+
} from './jira-tool.js';
|
|
78
|
+
|
|
79
|
+
// Notion tools
|
|
80
|
+
export {
|
|
81
|
+
NotionCreatePageTool,
|
|
82
|
+
NotionSearchTool,
|
|
83
|
+
NotionUpdatePageTool,
|
|
84
|
+
NotionToolkit,
|
|
85
|
+
} from './notion-tool.js';
|
|
86
|
+
|
|
87
|
+
// OpenAI tools
|
|
88
|
+
export {
|
|
89
|
+
OpenAIGenerateImageTool,
|
|
90
|
+
OpenAITranscribeAudioTool,
|
|
91
|
+
OpenAIToolkit,
|
|
92
|
+
} from './openai-tool.js';
|
|
93
|
+
|
|
94
|
+
// SerpApi tools
|
|
95
|
+
export {
|
|
96
|
+
SerpApiGoogleSearchTool,
|
|
97
|
+
SerpApiYouTubeSearchTool,
|
|
98
|
+
SerpApiToolkit,
|
|
99
|
+
} from './serpapi-tool.js';
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jira tool implementation - TypeScript JiraTools
|
|
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
|
+
* Jira API types
|
|
11
|
+
*/
|
|
12
|
+
interface JiraIssue {
|
|
13
|
+
key: string;
|
|
14
|
+
fields: {
|
|
15
|
+
summary: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
status: { name: string };
|
|
18
|
+
issuetype: { name: string };
|
|
19
|
+
assignee?: { displayName: string };
|
|
20
|
+
reporter?: { displayName: string };
|
|
21
|
+
project: { key: string };
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface JiraSearchResult {
|
|
26
|
+
issues: JiraIssue[];
|
|
27
|
+
total: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface JiraResult {
|
|
31
|
+
data?: unknown;
|
|
32
|
+
error?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Base Jira tool with common authentication
|
|
37
|
+
*/
|
|
38
|
+
abstract class BaseJiraTool<TParams extends z.ZodObject<Record<string, z.ZodType>>> extends BaseTool<TParams, JiraResult> {
|
|
39
|
+
protected serverUrl: string;
|
|
40
|
+
protected token: string;
|
|
41
|
+
protected email: string;
|
|
42
|
+
|
|
43
|
+
constructor(
|
|
44
|
+
config: Partial<Omit<BaseToolConfig<TParams>, 'parameters'>> & {
|
|
45
|
+
serverUrl?: string;
|
|
46
|
+
token?: string;
|
|
47
|
+
email?: string;
|
|
48
|
+
},
|
|
49
|
+
params: TParams
|
|
50
|
+
) {
|
|
51
|
+
super({
|
|
52
|
+
name: config.name || 'jira.tool',
|
|
53
|
+
description: config.description || 'Jira tool',
|
|
54
|
+
parameters: params,
|
|
55
|
+
category: config.category || ToolCategory.API,
|
|
56
|
+
permissions: {
|
|
57
|
+
allowNetwork: true,
|
|
58
|
+
maxExecutionTimeMs: 30000,
|
|
59
|
+
...config.permissions,
|
|
60
|
+
},
|
|
61
|
+
...config,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
this.serverUrl = config.serverUrl || process.env.JIRA_SERVER_URL || '';
|
|
65
|
+
this.token = config.token || process.env.JIRA_TOKEN || '';
|
|
66
|
+
this.email = config.email || process.env.JIRA_EMAIL || '';
|
|
67
|
+
|
|
68
|
+
if (!this.serverUrl) {
|
|
69
|
+
throw new Error('Jira server URL is required. Set JIRA_SERVER_URL environment variable or pass serverUrl in config.');
|
|
70
|
+
}
|
|
71
|
+
if (!this.token) {
|
|
72
|
+
throw new Error('Jira API token is required. Set JIRA_TOKEN environment variable or pass token in config.');
|
|
73
|
+
}
|
|
74
|
+
if (!this.email) {
|
|
75
|
+
throw new Error('Jira email is required. Set JIRA_EMAIL environment variable or pass email in config.');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
protected async jiraRequest(endpoint: string, options: RequestInit = {}): Promise<Response> {
|
|
80
|
+
const auth = Buffer.from(`${this.email}:${this.token}`).toString('base64');
|
|
81
|
+
|
|
82
|
+
return fetch(`${this.serverUrl}/rest/api/2${endpoint}`, {
|
|
83
|
+
...options,
|
|
84
|
+
headers: {
|
|
85
|
+
Authorization: `Basic ${auth}`,
|
|
86
|
+
'Content-Type': 'application/json',
|
|
87
|
+
Accept: 'application/json',
|
|
88
|
+
...(options.headers || {}),
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get issue tool
|
|
96
|
+
*/
|
|
97
|
+
const JiraGetIssueParameters = z.object({
|
|
98
|
+
issue_key: z.string().describe('The issue key (e.g., PROJ-123)'),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
export class JiraGetIssueTool extends BaseJiraTool<typeof JiraGetIssueParameters> {
|
|
102
|
+
constructor(
|
|
103
|
+
config?: Partial<Omit<BaseToolConfig<typeof JiraGetIssueParameters>, 'parameters'>> & {
|
|
104
|
+
serverUrl?: string;
|
|
105
|
+
token?: string;
|
|
106
|
+
email?: string;
|
|
107
|
+
}
|
|
108
|
+
) {
|
|
109
|
+
super(
|
|
110
|
+
{
|
|
111
|
+
name: config?.name ?? 'jira.get_issue',
|
|
112
|
+
description: config?.description ?? 'Get details of a Jira issue',
|
|
113
|
+
...config,
|
|
114
|
+
},
|
|
115
|
+
JiraGetIssueParameters
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
protected async performExecute(
|
|
120
|
+
params: z.infer<typeof JiraGetIssueParameters>,
|
|
121
|
+
_context: ToolContext
|
|
122
|
+
): Promise<JiraResult> {
|
|
123
|
+
try {
|
|
124
|
+
const response = await this.jiraRequest(`/issue/${encodeURIComponent(params.issue_key)}`);
|
|
125
|
+
|
|
126
|
+
if (!response.ok) {
|
|
127
|
+
throw new Error(`Jira API error: ${response.status}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const data = (await response.json()) as JiraIssue;
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
data: {
|
|
134
|
+
key: data.key,
|
|
135
|
+
summary: data.fields.summary,
|
|
136
|
+
description: data.fields.description,
|
|
137
|
+
status: data.fields.status.name,
|
|
138
|
+
issueType: data.fields.issuetype.name,
|
|
139
|
+
assignee: data.fields.assignee?.displayName,
|
|
140
|
+
reporter: data.fields.reporter?.displayName,
|
|
141
|
+
project: data.fields.project.key,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
} catch (error) {
|
|
145
|
+
return {
|
|
146
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Create issue tool
|
|
154
|
+
*/
|
|
155
|
+
const JiraCreateIssueParameters = z.object({
|
|
156
|
+
project_key: z.string().describe('The project key (e.g., PROJ)'),
|
|
157
|
+
summary: z.string().describe('The issue summary/title'),
|
|
158
|
+
description: z.string().optional().describe('The issue description'),
|
|
159
|
+
issue_type: z.string().optional().default('Task').describe('The issue type (e.g., Task, Bug, Story)'),
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
export class JiraCreateIssueTool extends BaseJiraTool<typeof JiraCreateIssueParameters> {
|
|
163
|
+
constructor(
|
|
164
|
+
config?: Partial<Omit<BaseToolConfig<typeof JiraCreateIssueParameters>, 'parameters'>> & {
|
|
165
|
+
serverUrl?: string;
|
|
166
|
+
token?: string;
|
|
167
|
+
email?: string;
|
|
168
|
+
}
|
|
169
|
+
) {
|
|
170
|
+
super(
|
|
171
|
+
{
|
|
172
|
+
name: config?.name ?? 'jira.create_issue',
|
|
173
|
+
description: config?.description ?? 'Create a new Jira issue',
|
|
174
|
+
...config,
|
|
175
|
+
},
|
|
176
|
+
JiraCreateIssueParameters
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
protected async performExecute(
|
|
181
|
+
params: z.infer<typeof JiraCreateIssueParameters>,
|
|
182
|
+
_context: ToolContext
|
|
183
|
+
): Promise<JiraResult> {
|
|
184
|
+
try {
|
|
185
|
+
const body = {
|
|
186
|
+
fields: {
|
|
187
|
+
project: { key: params.project_key },
|
|
188
|
+
summary: params.summary,
|
|
189
|
+
description: params.description,
|
|
190
|
+
issuetype: { name: params.issue_type },
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const response = await this.jiraRequest('/issue', {
|
|
195
|
+
method: 'POST',
|
|
196
|
+
body: JSON.stringify(body),
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
if (!response.ok) {
|
|
200
|
+
throw new Error(`Jira API error: ${response.status}`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const data = (await response.json()) as { key: string; self: string };
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
data: {
|
|
207
|
+
key: data.key,
|
|
208
|
+
url: `${this.serverUrl}/browse/${data.key}`,
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
} catch (error) {
|
|
212
|
+
return {
|
|
213
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Search issues tool
|
|
221
|
+
*/
|
|
222
|
+
const JiraSearchIssuesParameters = z.object({
|
|
223
|
+
jql: z.string().describe('JQL query string'),
|
|
224
|
+
max_results: z.number().min(1).max(100).optional().default(50).describe('Maximum number of results'),
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
export class JiraSearchIssuesTool extends BaseJiraTool<typeof JiraSearchIssuesParameters> {
|
|
228
|
+
constructor(
|
|
229
|
+
config?: Partial<Omit<BaseToolConfig<typeof JiraSearchIssuesParameters>, 'parameters'>> & {
|
|
230
|
+
serverUrl?: string;
|
|
231
|
+
token?: string;
|
|
232
|
+
email?: string;
|
|
233
|
+
}
|
|
234
|
+
) {
|
|
235
|
+
super(
|
|
236
|
+
{
|
|
237
|
+
name: config?.name ?? 'jira.search_issues',
|
|
238
|
+
description: config?.description ?? 'Search for issues using JQL',
|
|
239
|
+
...config,
|
|
240
|
+
},
|
|
241
|
+
JiraSearchIssuesParameters
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
protected async performExecute(
|
|
246
|
+
params: z.infer<typeof JiraSearchIssuesParameters>,
|
|
247
|
+
_context: ToolContext
|
|
248
|
+
): Promise<JiraResult> {
|
|
249
|
+
try {
|
|
250
|
+
const response = await this.jiraRequest(
|
|
251
|
+
`/search?jql=${encodeURIComponent(params.jql)}&maxResults=${params.max_results}`
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
if (!response.ok) {
|
|
255
|
+
throw new Error(`Jira API error: ${response.status}`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const data = (await response.json()) as JiraSearchResult;
|
|
259
|
+
|
|
260
|
+
const issues = data.issues.map((issue) => ({
|
|
261
|
+
key: issue.key,
|
|
262
|
+
summary: issue.fields.summary,
|
|
263
|
+
status: issue.fields.status.name,
|
|
264
|
+
assignee: issue.fields.assignee?.displayName || 'Unassigned',
|
|
265
|
+
}));
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
data: {
|
|
269
|
+
total: data.total,
|
|
270
|
+
issues,
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
} catch (error) {
|
|
274
|
+
return {
|
|
275
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Add comment tool
|
|
283
|
+
*/
|
|
284
|
+
const JiraAddCommentParameters = z.object({
|
|
285
|
+
issue_key: z.string().describe('The issue key'),
|
|
286
|
+
comment: z.string().describe('The comment text'),
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
export class JiraAddCommentTool extends BaseJiraTool<typeof JiraAddCommentParameters> {
|
|
290
|
+
constructor(
|
|
291
|
+
config?: Partial<Omit<BaseToolConfig<typeof JiraAddCommentParameters>, 'parameters'>> & {
|
|
292
|
+
serverUrl?: string;
|
|
293
|
+
token?: string;
|
|
294
|
+
email?: string;
|
|
295
|
+
}
|
|
296
|
+
) {
|
|
297
|
+
super(
|
|
298
|
+
{
|
|
299
|
+
name: config?.name ?? 'jira.add_comment',
|
|
300
|
+
description: config?.description ?? 'Add a comment to a Jira issue',
|
|
301
|
+
...config,
|
|
302
|
+
},
|
|
303
|
+
JiraAddCommentParameters
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
protected async performExecute(
|
|
308
|
+
params: z.infer<typeof JiraAddCommentParameters>,
|
|
309
|
+
_context: ToolContext
|
|
310
|
+
): Promise<JiraResult> {
|
|
311
|
+
try {
|
|
312
|
+
const response = await this.jiraRequest(`/issue/${encodeURIComponent(params.issue_key)}/comment`, {
|
|
313
|
+
method: 'POST',
|
|
314
|
+
body: JSON.stringify({ body: params.comment }),
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
if (!response.ok) {
|
|
318
|
+
throw new Error(`Jira API error: ${response.status}`);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const data = (await response.json()) as { id: string };
|
|
322
|
+
|
|
323
|
+
return {
|
|
324
|
+
data: {
|
|
325
|
+
commentId: data.id,
|
|
326
|
+
issueKey: params.issue_key,
|
|
327
|
+
},
|
|
328
|
+
};
|
|
329
|
+
} catch (error) {
|
|
330
|
+
return {
|
|
331
|
+
error: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Jira toolkit
|
|
339
|
+
*/
|
|
340
|
+
export class JiraToolkit {
|
|
341
|
+
static create(options?: {
|
|
342
|
+
serverUrl?: string;
|
|
343
|
+
token?: string;
|
|
344
|
+
email?: string;
|
|
345
|
+
enableGetIssue?: boolean;
|
|
346
|
+
enableCreateIssue?: boolean;
|
|
347
|
+
enableSearchIssues?: boolean;
|
|
348
|
+
enableAddComment?: boolean;
|
|
349
|
+
}): Array<JiraGetIssueTool | JiraCreateIssueTool | JiraSearchIssuesTool | JiraAddCommentTool> {
|
|
350
|
+
const tools: Array<JiraGetIssueTool | JiraCreateIssueTool | JiraSearchIssuesTool | JiraAddCommentTool> = [];
|
|
351
|
+
|
|
352
|
+
const config = {
|
|
353
|
+
serverUrl: options?.serverUrl,
|
|
354
|
+
token: options?.token,
|
|
355
|
+
email: options?.email,
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
if (options?.enableGetIssue !== false) {
|
|
359
|
+
tools.push(new JiraGetIssueTool(config));
|
|
360
|
+
}
|
|
361
|
+
if (options?.enableCreateIssue !== false) {
|
|
362
|
+
tools.push(new JiraCreateIssueTool(config));
|
|
363
|
+
}
|
|
364
|
+
if (options?.enableSearchIssues !== false) {
|
|
365
|
+
tools.push(new JiraSearchIssuesTool(config));
|
|
366
|
+
}
|
|
367
|
+
if (options?.enableAddComment !== false) {
|
|
368
|
+
tools.push(new JiraAddCommentTool(config));
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return tools;
|
|
372
|
+
}
|
|
373
|
+
}
|