@openenthrium/oe-runtime-sdk 1.7.5
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/README.md +139 -0
- package/index.js +58 -0
- package/package.json +64 -0
- package/src/data/connectionTypes.json +18587 -0
- package/src/engine/index.js +183 -0
- package/src/engine/llm.js +71 -0
- package/src/engine/promptBuilder.js +38 -0
- package/src/index.js +156 -0
- package/src/middleware/auth.js +63 -0
- package/src/providers/embedding/index.js +69 -0
- package/src/providers/llm/index.js +136 -0
- package/src/routes/admin.js +686 -0
- package/src/routes/agents.js +193 -0
- package/src/routes/apiKeys.js +55 -0
- package/src/routes/audio.js +111 -0
- package/src/routes/auth.js +83 -0
- package/src/routes/chat.js +381 -0
- package/src/routes/connectors.js +435 -0
- package/src/routes/dashboard.js +244 -0
- package/src/routes/documents.js +443 -0
- package/src/routes/embed.js +103 -0
- package/src/routes/marketplace.js +49 -0
- package/src/routes/models.js +81 -0
- package/src/routes/oauth.js +423 -0
- package/src/routes/projects.js +238 -0
- package/src/routes/settings.js +45 -0
- package/src/routes/setup.js +42 -0
- package/src/routes/sso.js +218 -0
- package/src/routes/superadmin.js +51 -0
- package/src/routes/templates.js +75 -0
- package/src/routes/threads.js +53 -0
- package/src/routes/workspaces.js +464 -0
- package/src/telemetry/bootstrap.js +39 -0
- package/src/telemetry/registration.js +16 -0
- package/src/utils/activityLog.js +16 -0
- package/src/utils/agentChain.js +141 -0
- package/src/utils/buildVisualization.js +102 -0
- package/src/utils/dlpScanner.js +57 -0
- package/src/utils/ingestionQueue.js +240 -0
- package/src/utils/prepareConnectors.js +66 -0
- package/src/utils/rag/_settings.js +6 -0
- package/src/utils/rag/chroma.js +82 -0
- package/src/utils/rag/lancedb.js +103 -0
- package/src/utils/rag/milvus.js +116 -0
- package/src/utils/rag/pgvector.js +104 -0
- package/src/utils/rag/pinecone.js +71 -0
- package/src/utils/rag/qdrant.js +106 -0
- package/src/utils/rag/weaviate.js +137 -0
- package/src/utils/rag/zilliz.js +115 -0
- package/src/utils/scheduler.js +168 -0
- package/src/utils/tier.js +106 -0
- package/src/utils/tools/adapters/_template.js +74 -0
- package/src/utils/tools/adapters/box.js +71 -0
- package/src/utils/tools/adapters/confluence.js +80 -0
- package/src/utils/tools/adapters/database.js +215 -0
- package/src/utils/tools/adapters/dropbox.js +74 -0
- package/src/utils/tools/adapters/elasticsearch.js +90 -0
- package/src/utils/tools/adapters/filesystem.js +197 -0
- package/src/utils/tools/adapters/freshdesk.js +87 -0
- package/src/utils/tools/adapters/gdrive.js +326 -0
- package/src/utils/tools/adapters/github.js +169 -0
- package/src/utils/tools/adapters/gmail.js +157 -0
- package/src/utils/tools/adapters/graphql.js +73 -0
- package/src/utils/tools/adapters/hubspot.js +101 -0
- package/src/utils/tools/adapters/image-gen.js +120 -0
- package/src/utils/tools/adapters/jira.js +86 -0
- package/src/utils/tools/adapters/kafka.js +126 -0
- package/src/utils/tools/adapters/ldap.js +118 -0
- package/src/utils/tools/adapters/mcp-client.js +138 -0
- package/src/utils/tools/adapters/mongodb.js +119 -0
- package/src/utils/tools/adapters/mqtt.js +106 -0
- package/src/utils/tools/adapters/music-gen.js +118 -0
- package/src/utils/tools/adapters/notion.js +93 -0
- package/src/utils/tools/adapters/ocr.js +107 -0
- package/src/utils/tools/adapters/onedrive.js +72 -0
- package/src/utils/tools/adapters/redis.js +104 -0
- package/src/utils/tools/adapters/rest-api.js +119 -0
- package/src/utils/tools/adapters/s3.js +142 -0
- package/src/utils/tools/adapters/search.js +80 -0
- package/src/utils/tools/adapters/sftp.js +121 -0
- package/src/utils/tools/adapters/shell.js +97 -0
- package/src/utils/tools/adapters/slack.js +83 -0
- package/src/utils/tools/adapters/speech.js +160 -0
- package/src/utils/tools/adapters/ssh.js +113 -0
- package/src/utils/tools/adapters/video-gen.js +152 -0
- package/src/utils/tools/adapters/web3.js +111 -0
- package/src/utils/tools/adapters/zendesk.js +82 -0
- package/src/utils/tools/adapters/zoho-mail.js +246 -0
- package/src/utils/tools/registry.js +229 -0
- package/src/utils/vectorStore.js +68 -0
- package/src/utils/workflowEngine.js +4 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
const { google } = require("googleapis");
|
|
2
|
+
|
|
3
|
+
async function getGoogleCredentials(db, workspaceId) {
|
|
4
|
+
let clientId = process.env.GOOGLE_CLIENT_ID;
|
|
5
|
+
let clientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
|
6
|
+
if (db && workspaceId) {
|
|
7
|
+
const rows = await db.setting.findMany({
|
|
8
|
+
where: { key: { in: [
|
|
9
|
+
`oauth.google.clientId.ws.${workspaceId}`,
|
|
10
|
+
`oauth.google.clientSecret.ws.${workspaceId}`,
|
|
11
|
+
]}}
|
|
12
|
+
});
|
|
13
|
+
for (const r of rows) {
|
|
14
|
+
if (r.key === `oauth.google.clientId.ws.${workspaceId}` && r.value) clientId = r.value;
|
|
15
|
+
if (r.key === `oauth.google.clientSecret.ws.${workspaceId}` && r.value) clientSecret = r.value;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return { clientId, clientSecret };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function makeOAuth2Client(db, workspaceId, callbackPath = "/api/oauth/gmail/callback", overrides = {}) {
|
|
22
|
+
const { clientId: dbId, clientSecret: dbSecret } = await getGoogleCredentials(db, workspaceId);
|
|
23
|
+
const clientId = overrides.clientId || dbId;
|
|
24
|
+
const clientSecret = overrides.clientSecret || dbSecret;
|
|
25
|
+
const callbackBase = process.env.OAUTH_CALLBACK_BASE || "http://localhost:3001";
|
|
26
|
+
return new google.auth.OAuth2(clientId, clientSecret, `${callbackBase}${callbackPath}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getToolDefinitions(connector) {
|
|
30
|
+
return [
|
|
31
|
+
{
|
|
32
|
+
type: "function",
|
|
33
|
+
function: {
|
|
34
|
+
name: `conn_${connector.id}_send_email`,
|
|
35
|
+
description: `Send an email via the connected Gmail account (${connector.name}). Use when the user asks to email, notify, or send a message.`,
|
|
36
|
+
parameters: {
|
|
37
|
+
type: "object",
|
|
38
|
+
properties: {
|
|
39
|
+
to: { type: "string", description: "Recipient email address." },
|
|
40
|
+
subject: { type: "string", description: "Email subject line." },
|
|
41
|
+
body: { type: "string", description: "Plain text email body." },
|
|
42
|
+
},
|
|
43
|
+
required: ["to", "subject", "body"]
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: "function",
|
|
49
|
+
function: {
|
|
50
|
+
name: `conn_${connector.id}_search_emails`,
|
|
51
|
+
description: `Search emails in the connected Gmail account (${connector.name}). Use when the user asks to find, look up, or check emails.`,
|
|
52
|
+
parameters: {
|
|
53
|
+
type: "object",
|
|
54
|
+
properties: {
|
|
55
|
+
query: { type: "string", description: "Gmail search query (e.g. 'from:someone@gmail.com subject:invoice')" },
|
|
56
|
+
maxResults: { type: "number", description: "Max emails to return (default 5, max 20)." },
|
|
57
|
+
},
|
|
58
|
+
required: ["query"]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getAnthropicToolDefinitions(connector) {
|
|
66
|
+
return [
|
|
67
|
+
{
|
|
68
|
+
name: `conn_${connector.id}_send_email`,
|
|
69
|
+
description: `Send an email via the connected Gmail account (${connector.name}).`,
|
|
70
|
+
input_schema: {
|
|
71
|
+
type: "object",
|
|
72
|
+
properties: {
|
|
73
|
+
to: { type: "string", description: "Recipient email address." },
|
|
74
|
+
subject: { type: "string", description: "Email subject line." },
|
|
75
|
+
body: { type: "string", description: "Plain text email body." },
|
|
76
|
+
},
|
|
77
|
+
required: ["to", "subject", "body"]
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: `conn_${connector.id}_search_emails`,
|
|
82
|
+
description: `Search emails in the connected Gmail account (${connector.name}).`,
|
|
83
|
+
input_schema: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {
|
|
86
|
+
query: { type: "string", description: "Gmail search query." },
|
|
87
|
+
maxResults: { type: "number", description: "Max emails to return (default 5, max 20)." },
|
|
88
|
+
},
|
|
89
|
+
required: ["query"]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function buildGmailClient(authConfig, db, workspaceId) {
|
|
96
|
+
const oauth2 = await makeOAuth2Client(db, workspaceId, "/api/oauth/gmail/callback", {
|
|
97
|
+
clientId: authConfig.clientId,
|
|
98
|
+
clientSecret: authConfig.clientSecret,
|
|
99
|
+
});
|
|
100
|
+
oauth2.setCredentials({
|
|
101
|
+
access_token: authConfig.accessToken,
|
|
102
|
+
refresh_token: authConfig.refreshToken,
|
|
103
|
+
expiry_date: authConfig.expiresAt,
|
|
104
|
+
});
|
|
105
|
+
return google.gmail({ version: "v1", auth: oauth2 });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function executeTool(action, args, connector, db) {
|
|
109
|
+
const authConfig = connector.authConfig ? JSON.parse(connector.authConfig) : {};
|
|
110
|
+
if (!authConfig.refreshToken) return "Gmail not connected. Please connect via the Integrations tab.";
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const gmail = await buildGmailClient(authConfig, db, connector.workspaceId);
|
|
114
|
+
|
|
115
|
+
if (action === "send_email") {
|
|
116
|
+
const { to, subject, body } = args;
|
|
117
|
+
if (!to || !subject || !body) return "Missing required fields: to, subject, body.";
|
|
118
|
+
|
|
119
|
+
const raw = Buffer.from(
|
|
120
|
+
`To: ${to}\r\nSubject: ${subject}\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n${body}`
|
|
121
|
+
).toString("base64url");
|
|
122
|
+
|
|
123
|
+
await gmail.users.messages.send({ userId: "me", requestBody: { raw } });
|
|
124
|
+
return `Email sent to ${to} with subject "${subject}".`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (action === "search_emails") {
|
|
128
|
+
const { query, maxResults = 5 } = args;
|
|
129
|
+
const safeMax = Math.min(parseInt(maxResults) || 5, 20);
|
|
130
|
+
|
|
131
|
+
const list = await gmail.users.messages.list({ userId: "me", q: query, maxResults: safeMax });
|
|
132
|
+
const messages = list.data.messages || [];
|
|
133
|
+
if (!messages.length) return `No emails found for query: "${query}"`;
|
|
134
|
+
|
|
135
|
+
const details = await Promise.all(
|
|
136
|
+
messages.map(m =>
|
|
137
|
+
gmail.users.messages.get({ userId: "me", id: m.id, format: "metadata",
|
|
138
|
+
metadataHeaders: ["From", "Subject", "Date"] })
|
|
139
|
+
)
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const results = details.map(r => {
|
|
143
|
+
const headers = r.data.payload?.headers || [];
|
|
144
|
+
const get = name => headers.find(h => h.name === name)?.value || "";
|
|
145
|
+
return { from: get("From"), subject: get("Subject"), date: get("Date"), snippet: r.data.snippet };
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
return JSON.stringify(results, null, 2);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return `Unknown Gmail action: ${action}`;
|
|
152
|
+
} catch (err) {
|
|
153
|
+
return `Gmail error: ${err.message}`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
module.exports = { getToolDefinitions, getAnthropicToolDefinitions, executeTool, makeOAuth2Client, getGoogleCredentials };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const axios = require("axios");
|
|
2
|
+
|
|
3
|
+
function getToolDefinitions(connector) {
|
|
4
|
+
return [
|
|
5
|
+
{
|
|
6
|
+
type: "function",
|
|
7
|
+
function: {
|
|
8
|
+
name: `conn_${connector.id}_query`,
|
|
9
|
+
description: `Run a GraphQL query against "${connector.name}".`,
|
|
10
|
+
parameters: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
query: { type: "string", description: "GraphQL query string" },
|
|
14
|
+
variables: { type: "object", description: "Optional variables", additionalProperties: true },
|
|
15
|
+
},
|
|
16
|
+
required: ["query"],
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
type: "function",
|
|
22
|
+
function: {
|
|
23
|
+
name: `conn_${connector.id}_mutate`,
|
|
24
|
+
description: `Run a GraphQL mutation against "${connector.name}".`,
|
|
25
|
+
parameters: {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
mutation: { type: "string", description: "GraphQL mutation string" },
|
|
29
|
+
variables: { type: "object", description: "Optional variables", additionalProperties: true },
|
|
30
|
+
},
|
|
31
|
+
required: ["mutation"],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function getAnthropicToolDefinitions(connector) {
|
|
39
|
+
return getToolDefinitions(connector).map(t => ({
|
|
40
|
+
name: t.function.name,
|
|
41
|
+
description: t.function.description,
|
|
42
|
+
input_schema: t.function.parameters,
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function executeTool(action, args, connector) {
|
|
47
|
+
const cfg = connector.config ? JSON.parse(connector.config) : {};
|
|
48
|
+
const auth = connector.authConfig ? JSON.parse(connector.authConfig) : {};
|
|
49
|
+
|
|
50
|
+
const endpoint = (cfg.baseUrl || auth.baseUrl || "").replace(/\/$/, "");
|
|
51
|
+
if (!endpoint) return "GraphQL endpoint (baseUrl) not configured.";
|
|
52
|
+
|
|
53
|
+
const headers = { "Content-Type": "application/json" };
|
|
54
|
+
if (auth.bearerToken) headers["Authorization"] = `Bearer ${auth.bearerToken}`;
|
|
55
|
+
if (auth.apiKey) headers[auth.headerName || "X-API-Key"] = auth.apiKey;
|
|
56
|
+
if (auth.headers) {
|
|
57
|
+
try { Object.assign(headers, typeof auth.headers === "string" ? JSON.parse(auth.headers) : auth.headers); } catch {}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const body = action === "query"
|
|
61
|
+
? { query: args.query, variables: args.variables || {} }
|
|
62
|
+
: { query: args.mutation, variables: args.variables || {} };
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const res = await axios.post(endpoint, body, { headers, timeout: 30000 });
|
|
66
|
+
if (res.data.errors) return `GraphQL errors: ${JSON.stringify(res.data.errors, null, 2)}`;
|
|
67
|
+
return JSON.stringify(res.data.data, null, 2).slice(0, 8000);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
return `GraphQL error: ${err.response?.status} ${err.response?.statusText || err.message}`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = { getToolDefinitions, getAnthropicToolDefinitions, executeTool };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
const axios = require("axios");
|
|
2
|
+
|
|
3
|
+
function cfg(connector) {
|
|
4
|
+
return connector.authConfig ? JSON.parse(connector.authConfig) : {};
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function client({ privateAppToken }) {
|
|
8
|
+
return axios.create({
|
|
9
|
+
baseURL: "https://api.hubapi.com",
|
|
10
|
+
headers: { Authorization: `Bearer ${privateAppToken}`, "Content-Type": "application/json" },
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const TOOLS = c => [
|
|
15
|
+
{ action: "search_contacts", desc: `Search HubSpot contacts via ${c.name}.`,
|
|
16
|
+
params: { query: { type: "string", description: "Search query (name, email, company)." } }, required: ["query"] },
|
|
17
|
+
{ action: "get_contact", desc: `Get a HubSpot contact by ID via ${c.name}.`,
|
|
18
|
+
params: { contactId: { type: "string", description: "HubSpot contact ID." } }, required: ["contactId"] },
|
|
19
|
+
{ action: "create_contact", desc: `Create a HubSpot contact via ${c.name}.`,
|
|
20
|
+
params: { email: { type: "string", description: "Contact email." },
|
|
21
|
+
firstName: { type: "string", description: "First name." },
|
|
22
|
+
lastName: { type: "string", description: "Last name." },
|
|
23
|
+
company: { type: "string", description: "Company name." } }, required: ["email"] },
|
|
24
|
+
{ action: "search_deals", desc: `Search HubSpot deals via ${c.name}.`,
|
|
25
|
+
params: { query: { type: "string", description: "Deal name or keyword." } }, required: ["query"] },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
function getToolDefinitions(connector) {
|
|
29
|
+
return TOOLS(connector).map(t => ({
|
|
30
|
+
type: "function",
|
|
31
|
+
function: { name: `conn_${connector.id}_${t.action}`, description: t.desc,
|
|
32
|
+
parameters: { type: "object", properties: t.params, required: t.required } },
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getAnthropicToolDefinitions(connector) {
|
|
37
|
+
return TOOLS(connector).map(t => ({
|
|
38
|
+
name: `conn_${connector.id}_${t.action}`, description: t.desc,
|
|
39
|
+
input_schema: { type: "object", properties: t.params, required: t.required },
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function executeTool(action, args, connector) {
|
|
44
|
+
const creds = cfg(connector);
|
|
45
|
+
if (!creds.privateAppToken) return "HubSpot not configured. Please add credentials in Integrations.";
|
|
46
|
+
const api = client(creds);
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
if (action === "search_contacts") {
|
|
50
|
+
const res = await api.post("/crm/v3/objects/contacts/search", {
|
|
51
|
+
query: args.query, limit: 10,
|
|
52
|
+
properties: ["firstname","lastname","email","company","phone"],
|
|
53
|
+
});
|
|
54
|
+
const results = res.data.results || [];
|
|
55
|
+
if (!results.length) return "No contacts found.";
|
|
56
|
+
return results.map(r => {
|
|
57
|
+
const p = r.properties;
|
|
58
|
+
return `[${r.id}] ${p.firstname || ""} ${p.lastname || ""} <${p.email}> — ${p.company || ""}`;
|
|
59
|
+
}).join("\n");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (action === "get_contact") {
|
|
63
|
+
const res = await api.get(`/crm/v3/objects/contacts/${args.contactId}?properties=firstname,lastname,email,company,phone,createdate`);
|
|
64
|
+
return JSON.stringify(res.data.properties, null, 2);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (action === "create_contact") {
|
|
68
|
+
const { email, firstName = "", lastName = "", company = "" } = args;
|
|
69
|
+
const res = await api.post("/crm/v3/objects/contacts", {
|
|
70
|
+
properties: { email, firstname: firstName, lastname: lastName, company },
|
|
71
|
+
});
|
|
72
|
+
return `Created contact: ${firstName} ${lastName} <${email}> (ID: ${res.data.id})`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (action === "search_deals") {
|
|
76
|
+
const res = await api.post("/crm/v3/objects/deals/search", {
|
|
77
|
+
query: args.query, limit: 10,
|
|
78
|
+
properties: ["dealname","amount","dealstage","closedate"],
|
|
79
|
+
});
|
|
80
|
+
const results = res.data.results || [];
|
|
81
|
+
if (!results.length) return "No deals found.";
|
|
82
|
+
return results.map(r => {
|
|
83
|
+
const p = r.properties;
|
|
84
|
+
return `[${r.id}] ${p.dealname} — Stage: ${p.dealstage}, Amount: ${p.amount || "N/A"}`;
|
|
85
|
+
}).join("\n");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return `Unknown HubSpot action: ${action}`;
|
|
89
|
+
} catch (err) {
|
|
90
|
+
return `HubSpot error: ${err.response?.data?.message || err.message}`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function testConnection(authConfig) {
|
|
95
|
+
try {
|
|
96
|
+
const res = await client(authConfig).get("/crm/v3/objects/contacts?limit=1");
|
|
97
|
+
return Array.isArray(res.data.results);
|
|
98
|
+
} catch { return false; }
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = { getToolDefinitions, getAnthropicToolDefinitions, executeTool, testConnection };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const axios = require("axios");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const os = require("os");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
|
|
7
|
+
function getToolDefinitions(connector) {
|
|
8
|
+
return [
|
|
9
|
+
{
|
|
10
|
+
type: "function",
|
|
11
|
+
function: {
|
|
12
|
+
name: `conn_${connector.id}_generate_image`,
|
|
13
|
+
description: `Generate an image from a text prompt using "${connector.name}". Returns the image URL.`,
|
|
14
|
+
parameters: {
|
|
15
|
+
type: "object",
|
|
16
|
+
properties: {
|
|
17
|
+
prompt: { type: "string", description: "Detailed description of the image to generate. Include all style, mood, and visual direction here (e.g. minimalist, bold, photorealistic)." },
|
|
18
|
+
size: { type: "string", description: "Image size: '1024x1024', '1792x1024', or '1024x1792'" },
|
|
19
|
+
dalle_style: { type: "string", description: "OpenAI DALL-E rendering style only: 'vivid' (hyper-real) or 'natural' (realistic). Do NOT use brand style words here — put those in the prompt." },
|
|
20
|
+
n: { type: "number", description: "Number of images to generate (default 1, max 4)" },
|
|
21
|
+
},
|
|
22
|
+
required: ["prompt"],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getAnthropicToolDefinitions(connector) {
|
|
30
|
+
return getToolDefinitions(connector).map(t => ({
|
|
31
|
+
name: t.function.name,
|
|
32
|
+
description: t.function.description,
|
|
33
|
+
input_schema: t.function.parameters,
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function executeTool(action, args, connector) {
|
|
38
|
+
const auth = connector.authConfig ? JSON.parse(connector.authConfig) : {};
|
|
39
|
+
const cfg = connector.config ? JSON.parse(connector.config) : {};
|
|
40
|
+
const creds = { ...cfg, ...auth };
|
|
41
|
+
const type = connector.type;
|
|
42
|
+
|
|
43
|
+
if (action !== "generate_image") return `Unknown action: ${action}`;
|
|
44
|
+
|
|
45
|
+
const prompt = args.prompt || "";
|
|
46
|
+
const n = Math.min(args.n || 1, 4);
|
|
47
|
+
const size = args.size || "1024x1024";
|
|
48
|
+
|
|
49
|
+
// ── OpenAI DALL-E / GPT-Image ─────────────────────────────────────────────
|
|
50
|
+
if (type === "openai-image") {
|
|
51
|
+
const model = creds.model || "gpt-image-1";
|
|
52
|
+
const dalleStyle = ["vivid", "natural"].includes(args.dalle_style) ? args.dalle_style : "vivid";
|
|
53
|
+
const body = { model, prompt, n: model === "dall-e-3" ? 1 : n, size };
|
|
54
|
+
let resp;
|
|
55
|
+
try {
|
|
56
|
+
resp = await axios.post(
|
|
57
|
+
"https://api.openai.com/v1/images/generations",
|
|
58
|
+
body,
|
|
59
|
+
{ headers: { Authorization: `Bearer ${creds.apiKey}`, "Content-Type": "application/json" } }
|
|
60
|
+
);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
const detail = err.response?.data?.error?.message || err.response?.data || err.message;
|
|
63
|
+
return `OpenAI image error (${err.response?.status}): ${typeof detail === "object" ? JSON.stringify(detail) : detail}`;
|
|
64
|
+
}
|
|
65
|
+
const results = [];
|
|
66
|
+
for (const d of (resp.data.data || [])) {
|
|
67
|
+
if (d.url) {
|
|
68
|
+
results.push(`Image URL: ${d.url}`);
|
|
69
|
+
} else if (d.b64_json) {
|
|
70
|
+
const outFile = path.join(os.tmpdir(), `oe-image-${Date.now()}.png`);
|
|
71
|
+
fs.writeFileSync(outFile, Buffer.from(d.b64_json, "base64"));
|
|
72
|
+
results.push(`Image saved to: ${outFile}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return results.length ? results.join("\n") : "Image generated but no URL or data returned.";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ── FLUX (via Together AI) ────────────────────────────────────────────────
|
|
79
|
+
if (type === "flux") {
|
|
80
|
+
const model = creds.model || "black-forest-labs/FLUX.1-schnell-Free";
|
|
81
|
+
const resp = await axios.post(
|
|
82
|
+
"https://api.together.xyz/v1/images/generations",
|
|
83
|
+
{ model, prompt, n, width: 1024, height: 1024, steps: 4 },
|
|
84
|
+
{ headers: { Authorization: `Bearer ${creds.apiKey}`, "Content-Type": "application/json" } }
|
|
85
|
+
);
|
|
86
|
+
const urls = (resp.data.data || []).map(d => d.url || d.b64_json);
|
|
87
|
+
return urls.length === 1 ? `Image generated: ${urls[0]}` : urls.map((u, i) => `Image ${i + 1}: ${u}`).join("\n");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── Stable Diffusion (Stability AI) ──────────────────────────────────────
|
|
91
|
+
if (type === "stable-diffusion") {
|
|
92
|
+
const [w, h] = (size || "1024x1024").split("x").map(Number);
|
|
93
|
+
const resp = await axios.post(
|
|
94
|
+
"https://api.stability.ai/v2beta/stable-image/generate/core",
|
|
95
|
+
{ prompt, output_format: "webp", aspect_ratio: w >= h ? "16:9" : "9:16" },
|
|
96
|
+
{
|
|
97
|
+
headers: { Authorization: `Bearer ${creds.apiKey}`, Accept: "application/json" },
|
|
98
|
+
responseType: "json",
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
const image = resp.data.image;
|
|
102
|
+
if (!image) return "Stable Diffusion returned no image.";
|
|
103
|
+
return `Image generated (base64 webp, ${image.length} chars). You can embed it as: data:image/webp;base64,${image.slice(0, 40)}...`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ── Ideogram ──────────────────────────────────────────────────────────────
|
|
107
|
+
if (type === "ideogram") {
|
|
108
|
+
const resp = await axios.post(
|
|
109
|
+
"https://api.ideogram.ai/generate",
|
|
110
|
+
{ image_request: { prompt, resolution: "RESOLUTION_1024_1024", style_type: args.style || "REALISTIC", num_images: n } },
|
|
111
|
+
{ headers: { "Api-Key": creds.apiKey, "Content-Type": "application/json" } }
|
|
112
|
+
);
|
|
113
|
+
const urls = (resp.data.data || []).map(d => d.url);
|
|
114
|
+
return urls.length === 1 ? `Image generated: ${urls[0]}` : urls.map((u, i) => `Image ${i + 1}: ${u}`).join("\n");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return `Unsupported image generation connector type: ${type}`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
module.exports = { getToolDefinitions, getAnthropicToolDefinitions, executeTool };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const axios = require("axios");
|
|
2
|
+
|
|
3
|
+
function cfg(connector) {
|
|
4
|
+
return connector.authConfig ? JSON.parse(connector.authConfig) : {};
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function client({ domain, email, apiToken }) {
|
|
8
|
+
return axios.create({
|
|
9
|
+
baseURL: `https://${domain}/rest/api/3`,
|
|
10
|
+
auth: { username: email, password: apiToken },
|
|
11
|
+
headers: { "Content-Type": "application/json" },
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const TOOLS = c => [
|
|
16
|
+
{ action: "search_issues", desc: `Search Jira issues via ${c.name} using JQL.`,
|
|
17
|
+
params: { jql: { type: "string", description: "JQL query (e.g. project=MYPROJ AND status=Open)" },
|
|
18
|
+
maxResults: { type: "number", description: "Max results (default 10)." } }, required: ["jql"] },
|
|
19
|
+
{ action: "get_issue", desc: `Get details of a Jira issue via ${c.name}.`,
|
|
20
|
+
params: { issueKey: { type: "string", description: "Issue key (e.g. PROJ-123)" } }, required: ["issueKey"] },
|
|
21
|
+
{ action: "create_issue", desc: `Create a Jira issue via ${c.name}.`,
|
|
22
|
+
params: { project: { type: "string", description: "Project key (e.g. PROJ)" },
|
|
23
|
+
summary: { type: "string", description: "Issue summary/title." },
|
|
24
|
+
description: { type: "string", description: "Issue description." },
|
|
25
|
+
issueType: { type: "string", description: "Issue type (e.g. Bug, Task, Story). Default: Task." } },
|
|
26
|
+
required: ["project","summary"] },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
function getToolDefinitions(connector) {
|
|
30
|
+
return TOOLS(connector).map(t => ({
|
|
31
|
+
type: "function",
|
|
32
|
+
function: { name: `conn_${connector.id}_${t.action}`, description: t.desc,
|
|
33
|
+
parameters: { type: "object", properties: t.params, required: t.required } },
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getAnthropicToolDefinitions(connector) {
|
|
38
|
+
return TOOLS(connector).map(t => ({
|
|
39
|
+
name: `conn_${connector.id}_${t.action}`, description: t.desc,
|
|
40
|
+
input_schema: { type: "object", properties: t.params, required: t.required },
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function executeTool(action, args, connector) {
|
|
45
|
+
const creds = cfg(connector);
|
|
46
|
+
if (!creds.domain || !creds.apiToken) return "Jira not configured. Please add credentials in Integrations.";
|
|
47
|
+
const api = client(creds);
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
if (action === "search_issues") {
|
|
51
|
+
const { jql, maxResults = 10 } = args;
|
|
52
|
+
const res = await api.get(`/search?jql=${encodeURIComponent(jql)}&maxResults=${Math.min(maxResults, 25)}&fields=summary,status,assignee,priority`);
|
|
53
|
+
const issues = res.data.issues || [];
|
|
54
|
+
if (!issues.length) return "No issues found.";
|
|
55
|
+
return issues.map(i => `${i.key}: ${i.fields.summary} [${i.fields.status?.name}]`).join("\n");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (action === "get_issue") {
|
|
59
|
+
const res = await api.get(`/issue/${args.issueKey}`);
|
|
60
|
+
const f = res.data.fields;
|
|
61
|
+
return JSON.stringify({ key: res.data.key, summary: f.summary, status: f.status?.name, assignee: f.assignee?.displayName, priority: f.priority?.name, description: f.description }, null, 2);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (action === "create_issue") {
|
|
65
|
+
const { project, summary, description = "", issueType = "Task" } = args;
|
|
66
|
+
const res = await api.post("/issue", {
|
|
67
|
+
fields: { project: { key: project }, summary, issuetype: { name: issueType },
|
|
68
|
+
description: { type: "doc", version: 1, content: [{ type: "paragraph", content: [{ type: "text", text: description }] }] } },
|
|
69
|
+
});
|
|
70
|
+
return `Created issue ${res.data.key}: ${summary}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return `Unknown Jira action: ${action}`;
|
|
74
|
+
} catch (err) {
|
|
75
|
+
return `Jira error: ${err.response?.data?.errorMessages?.join(", ") || err.message}`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function testConnection(authConfig) {
|
|
80
|
+
try {
|
|
81
|
+
const res = await client(authConfig).get("/myself");
|
|
82
|
+
return !!res.data.accountId;
|
|
83
|
+
} catch { return false; }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = { getToolDefinitions, getAnthropicToolDefinitions, executeTool, testConnection };
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const { Kafka } = require("kafkajs");
|
|
2
|
+
|
|
3
|
+
function getClient(connector) {
|
|
4
|
+
const auth = connector.authConfig ? JSON.parse(connector.authConfig) : {};
|
|
5
|
+
const cfg = connector.config ? JSON.parse(connector.config) : {};
|
|
6
|
+
|
|
7
|
+
const brokers = (auth.brokers || cfg.brokers || auth.baseUrl || cfg.baseUrl || "localhost:9092")
|
|
8
|
+
.split(",").map(b => b.trim().replace(/^https?:\/\//, ""));
|
|
9
|
+
const clientId = auth.clientId || cfg.clientId || "open-enthrium";
|
|
10
|
+
|
|
11
|
+
const kafkaCfg = { clientId, brokers };
|
|
12
|
+
|
|
13
|
+
const username = auth.username || cfg.username;
|
|
14
|
+
const password = auth.password || cfg.password;
|
|
15
|
+
if (username && password) {
|
|
16
|
+
kafkaCfg.ssl = true;
|
|
17
|
+
kafkaCfg.sasl = { mechanism: "plain", username, password };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return { kafka: new Kafka(kafkaCfg), defaultTopic: auth.topic || cfg.topic || "" };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getToolDefinitions(connector) {
|
|
24
|
+
return [
|
|
25
|
+
{
|
|
26
|
+
type: "function",
|
|
27
|
+
function: {
|
|
28
|
+
name: `conn_${connector.id}_produce`,
|
|
29
|
+
description: `Publish a message to a Kafka topic on "${connector.name}".`,
|
|
30
|
+
parameters: {
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: {
|
|
33
|
+
topic: { type: "string", description: "Topic name" },
|
|
34
|
+
message: { type: "string", description: "Message value (string or JSON string)" },
|
|
35
|
+
key: { type: "string", description: "Optional message key" },
|
|
36
|
+
},
|
|
37
|
+
required: ["message"],
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
type: "function",
|
|
43
|
+
function: {
|
|
44
|
+
name: `conn_${connector.id}_consume`,
|
|
45
|
+
description: `Read recent messages from a Kafka topic on "${connector.name}".`,
|
|
46
|
+
parameters: {
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: {
|
|
49
|
+
topic: { type: "string", description: "Topic name" },
|
|
50
|
+
limit: { type: "number", description: "Max messages to read (default 10)" },
|
|
51
|
+
},
|
|
52
|
+
required: [],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
type: "function",
|
|
58
|
+
function: {
|
|
59
|
+
name: `conn_${connector.id}_list_topics`,
|
|
60
|
+
description: `List all topics on the Kafka cluster "${connector.name}".`,
|
|
61
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getAnthropicToolDefinitions(connector) {
|
|
68
|
+
return getToolDefinitions(connector).map(t => ({
|
|
69
|
+
name: t.function.name,
|
|
70
|
+
description: t.function.description,
|
|
71
|
+
input_schema: t.function.parameters,
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function executeTool(action, args, connector) {
|
|
76
|
+
const { kafka, defaultTopic } = getClient(connector);
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
if (action === "produce") {
|
|
80
|
+
const topic = args.topic || defaultTopic;
|
|
81
|
+
if (!topic) return "Topic name required.";
|
|
82
|
+
const producer = kafka.producer();
|
|
83
|
+
await producer.connect();
|
|
84
|
+
await producer.send({ topic, messages: [{ key: args.key || null, value: args.message }] });
|
|
85
|
+
await producer.disconnect();
|
|
86
|
+
return `Message published to topic "${topic}".`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (action === "consume") {
|
|
90
|
+
const topic = args.topic || defaultTopic;
|
|
91
|
+
if (!topic) return "Topic name required.";
|
|
92
|
+
const limit = Math.min(parseInt(args.limit) || 10, 50);
|
|
93
|
+
const groupId = `oe-consumer-${Date.now()}`;
|
|
94
|
+
const consumer = kafka.consumer({ groupId });
|
|
95
|
+
await consumer.connect();
|
|
96
|
+
await consumer.subscribe({ topic, fromBeginning: false });
|
|
97
|
+
|
|
98
|
+
const messages = [];
|
|
99
|
+
await new Promise((resolve) => {
|
|
100
|
+
consumer.run({
|
|
101
|
+
eachMessage: async ({ message }) => {
|
|
102
|
+
messages.push(`[${message.offset}] ${message.value?.toString()}`);
|
|
103
|
+
if (messages.length >= limit) resolve();
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
setTimeout(resolve, 5000);
|
|
107
|
+
});
|
|
108
|
+
await consumer.disconnect();
|
|
109
|
+
return messages.length ? messages.join("\n") : "No messages received.";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (action === "list_topics") {
|
|
113
|
+
const admin = kafka.admin();
|
|
114
|
+
await admin.connect();
|
|
115
|
+
const topics = await admin.listTopics();
|
|
116
|
+
await admin.disconnect();
|
|
117
|
+
return topics.join("\n") || "No topics found.";
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return `Unknown Kafka action: ${action}`;
|
|
121
|
+
} catch (err) {
|
|
122
|
+
return `Kafka error: ${err.message}`;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
module.exports = { getToolDefinitions, getAnthropicToolDefinitions, executeTool };
|