@alephantai/n8n-nodes-alephant-analytics-ai 0.1.2 → 0.1.4
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/dist/nodes/AlephantAnalyticsAi/AlephantAnalyticsAi.node.d.ts +2 -1
- package/dist/nodes/AlephantAnalyticsAi/AlephantAnalyticsAi.node.js +91 -0
- package/dist/shared/errors.d.ts +2 -2
- package/dist/shared/http.d.ts +2 -2
- package/dist/shared/usage.d.ts +8 -1
- package/dist/shared/usage.js +53 -46
- package/package.json +4 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
1
|
+
import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription, ISupplyDataFunctions, SupplyData } from 'n8n-workflow';
|
|
2
2
|
export declare class AlephantAnalyticsAi implements INodeType {
|
|
3
3
|
description: INodeTypeDescription;
|
|
4
|
+
supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData>;
|
|
4
5
|
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
6
|
}
|
|
@@ -1,8 +1,68 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AlephantAnalyticsAi = void 0;
|
|
4
|
+
const tools_1 = require("@langchain/core/tools");
|
|
4
5
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
6
|
const usage_1 = require("../../shared/usage");
|
|
7
|
+
function toSafeToolName(nodeName) {
|
|
8
|
+
const normalized = (0, n8n_workflow_1.nodeNameToToolName)(nodeName)
|
|
9
|
+
.replace(/[^A-Za-z0-9_]/g, '_')
|
|
10
|
+
.replace(/^[^A-Za-z_]+/, '');
|
|
11
|
+
return normalized || 'Alephant_Analytics_AI';
|
|
12
|
+
}
|
|
13
|
+
function readToolInput(input) {
|
|
14
|
+
return typeof input === 'object' && input !== null ? input : {};
|
|
15
|
+
}
|
|
16
|
+
function readString(value, fallback) {
|
|
17
|
+
return typeof value === 'string' && value.trim() !== '' ? value : fallback;
|
|
18
|
+
}
|
|
19
|
+
function readNumber(value, fallback) {
|
|
20
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
|
|
21
|
+
}
|
|
22
|
+
const analyticsToolSchema = {
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
operation: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
enum: [
|
|
28
|
+
'scope',
|
|
29
|
+
'budgetStatus',
|
|
30
|
+
'usageSummary',
|
|
31
|
+
'dailyCosts',
|
|
32
|
+
'costByModel',
|
|
33
|
+
'recentRequests',
|
|
34
|
+
'requestLogDetail',
|
|
35
|
+
],
|
|
36
|
+
description: 'Alephant analytics operation to run.',
|
|
37
|
+
default: 'usageSummary',
|
|
38
|
+
},
|
|
39
|
+
period: {
|
|
40
|
+
type: 'string',
|
|
41
|
+
enum: ['24h', '7d', '30d', '90d'],
|
|
42
|
+
description: 'Time period for budget, usage, daily cost, and cost-by-model operations.',
|
|
43
|
+
default: '7d',
|
|
44
|
+
},
|
|
45
|
+
limit: {
|
|
46
|
+
type: 'integer',
|
|
47
|
+
minimum: 1,
|
|
48
|
+
description: 'Maximum recent requests to return.',
|
|
49
|
+
},
|
|
50
|
+
offset: {
|
|
51
|
+
type: 'integer',
|
|
52
|
+
minimum: 0,
|
|
53
|
+
description: 'Recent requests offset.',
|
|
54
|
+
},
|
|
55
|
+
requestLogId: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: 'Request log ID for requestLogDetail.',
|
|
58
|
+
},
|
|
59
|
+
workspaceId: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
description: 'Workspace ID for request log detail lookups when credentials do not include one.',
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
additionalProperties: false,
|
|
65
|
+
};
|
|
6
66
|
class AlephantAnalyticsAi {
|
|
7
67
|
constructor() {
|
|
8
68
|
this.description = {
|
|
@@ -101,6 +161,37 @@ class AlephantAnalyticsAi {
|
|
|
101
161
|
],
|
|
102
162
|
};
|
|
103
163
|
}
|
|
164
|
+
async supplyData(itemIndex) {
|
|
165
|
+
const name = toSafeToolName(this.getNode().name);
|
|
166
|
+
try {
|
|
167
|
+
(0, n8n_workflow_1.tryToParseAlphanumericString)(name);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'The name of this tool is not a valid alphanumeric string', {
|
|
171
|
+
itemIndex,
|
|
172
|
+
description: "Only alphanumeric characters and underscores are allowed in the tool's name, and the name cannot start with a number",
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
response: new tools_1.DynamicStructuredTool({
|
|
177
|
+
name,
|
|
178
|
+
description: 'Query Alephant AI analytics for usage, cost, latency, model/provider performance, budget status, recent requests, and request log detail.',
|
|
179
|
+
schema: analyticsToolSchema,
|
|
180
|
+
func: async (input) => {
|
|
181
|
+
const toolInput = readToolInput(input);
|
|
182
|
+
const data = await (0, usage_1.runUsageRequest)(this, {
|
|
183
|
+
operation: readString(toolInput.operation, 'usageSummary'),
|
|
184
|
+
period: readString(toolInput.period, '7d'),
|
|
185
|
+
limit: readNumber(toolInput.limit, 50),
|
|
186
|
+
offset: readNumber(toolInput.offset, 0),
|
|
187
|
+
requestLogId: readString(toolInput.requestLogId, ''),
|
|
188
|
+
workspaceId: readString(toolInput.workspaceId, ''),
|
|
189
|
+
}, itemIndex);
|
|
190
|
+
return JSON.stringify(data);
|
|
191
|
+
},
|
|
192
|
+
}),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
104
195
|
async execute() {
|
|
105
196
|
return usage_1.executeUsageNode.call(this);
|
|
106
197
|
}
|
package/dist/shared/errors.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { NodeApiError } from 'n8n-workflow';
|
|
2
|
-
import type { IExecuteFunctions, IHttpRequestMethods } from 'n8n-workflow';
|
|
3
|
-
export declare function toNodeApiError(ctx: IExecuteFunctions, error: unknown, method: IHttpRequestMethods, url: string, itemIndex?: number): NodeApiError;
|
|
2
|
+
import type { IExecuteFunctions, IHttpRequestMethods, ISupplyDataFunctions } from 'n8n-workflow';
|
|
3
|
+
export declare function toNodeApiError(ctx: IExecuteFunctions | ISupplyDataFunctions, error: unknown, method: IHttpRequestMethods, url: string, itemIndex?: number): NodeApiError;
|
package/dist/shared/http.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IDataObject, IExecuteFunctions, IHttpRequestMethods } from 'n8n-workflow';
|
|
1
|
+
import type { IDataObject, IExecuteFunctions, IHttpRequestMethods, ISupplyDataFunctions } from 'n8n-workflow';
|
|
2
2
|
export interface AlephantRequestOptions {
|
|
3
3
|
method: IHttpRequestMethods;
|
|
4
4
|
baseUrl: string;
|
|
@@ -10,4 +10,4 @@ export interface AlephantRequestOptions {
|
|
|
10
10
|
body?: IDataObject;
|
|
11
11
|
itemIndex?: number;
|
|
12
12
|
}
|
|
13
|
-
export declare function alephantRequest<T>(ctx: IExecuteFunctions, options: AlephantRequestOptions): Promise<T>;
|
|
13
|
+
export declare function alephantRequest<T>(ctx: IExecuteFunctions | ISupplyDataFunctions, options: AlephantRequestOptions): Promise<T>;
|
package/dist/shared/usage.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IDataObject, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
|
|
1
|
+
import type { IDataObject, IExecuteFunctions, INodeExecutionData, ISupplyDataFunctions } from 'n8n-workflow';
|
|
2
2
|
export type UsageOperation = 'scope' | 'budgetStatus' | 'usageSummary' | 'dailyCosts' | 'costByModel' | 'recentRequests' | 'requestLogDetail';
|
|
3
3
|
export interface UsageRequestParams {
|
|
4
4
|
period?: string | null;
|
|
@@ -6,10 +6,17 @@ export interface UsageRequestParams {
|
|
|
6
6
|
offset?: number | null;
|
|
7
7
|
requestLogId?: string | null;
|
|
8
8
|
}
|
|
9
|
+
export interface UsageToolInput extends UsageRequestParams {
|
|
10
|
+
operation: UsageOperation;
|
|
11
|
+
requestLogMaxAttempts?: number | null;
|
|
12
|
+
workspaceId?: string | null;
|
|
13
|
+
inputJson?: IDataObject;
|
|
14
|
+
}
|
|
9
15
|
export interface UsageRequest {
|
|
10
16
|
host?: 'saas' | 'analytics';
|
|
11
17
|
path: string;
|
|
12
18
|
qs?: IDataObject;
|
|
13
19
|
}
|
|
14
20
|
export declare function buildUsageRequest(operation: UsageOperation, params: UsageRequestParams): UsageRequest;
|
|
21
|
+
export declare function runUsageRequest(ctx: IExecuteFunctions | ISupplyDataFunctions, params: UsageToolInput, itemIndex?: number): Promise<IDataObject>;
|
|
15
22
|
export declare function executeUsageNode(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
package/dist/shared/usage.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.buildUsageRequest = buildUsageRequest;
|
|
4
|
+
exports.runUsageRequest = runUsageRequest;
|
|
4
5
|
exports.executeUsageNode = executeUsageNode;
|
|
5
6
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
6
7
|
const constants_1 = require("./constants");
|
|
@@ -111,56 +112,62 @@ function buildUsageRequest(operation, params) {
|
|
|
111
112
|
};
|
|
112
113
|
}
|
|
113
114
|
}
|
|
115
|
+
async function runUsageRequest(ctx, params, itemIndex = 0) {
|
|
116
|
+
const credentials = (0, credentials_1.resolveVirtualKeyCredentials)((await ctx.getCredentials('alephantVirtualKeyApi')));
|
|
117
|
+
let request;
|
|
118
|
+
try {
|
|
119
|
+
request = buildUsageRequest(params.operation, params);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), error instanceof Error ? error.message : 'Invalid Alephant Usage input', { itemIndex });
|
|
123
|
+
}
|
|
124
|
+
let workspaceId = request.host === 'analytics'
|
|
125
|
+
? normalizeOptionalString(params.workspaceId) ||
|
|
126
|
+
normalizeOptionalString(params.inputJson?.workspaceId) ||
|
|
127
|
+
normalizeOptionalString(params.inputJson?.workspace_id) ||
|
|
128
|
+
normalizeOptionalString(params.inputJson?.xWorkspaceId) ||
|
|
129
|
+
credentials.workspaceId
|
|
130
|
+
: undefined;
|
|
131
|
+
if (request.host === 'analytics' && workspaceId === '') {
|
|
132
|
+
const scope = await (0, http_1.alephantRequest)(ctx, {
|
|
133
|
+
method: 'GET',
|
|
134
|
+
baseUrl: credentials.saasBaseUrl,
|
|
135
|
+
path: constants_1.ENDPOINTS.cockpitScope,
|
|
136
|
+
token: credentials.virtualKey,
|
|
137
|
+
itemIndex,
|
|
138
|
+
});
|
|
139
|
+
workspaceId = extractWorkspaceIdFromScope(scope);
|
|
140
|
+
}
|
|
141
|
+
if (request.host === 'analytics' && workspaceId === '') {
|
|
142
|
+
throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Workspace ID is required for request log detail lookups and could not be resolved from Alephant Scope', { itemIndex });
|
|
143
|
+
}
|
|
144
|
+
const requestOptions = {
|
|
145
|
+
method: 'GET',
|
|
146
|
+
baseUrl: request.host === 'analytics' ? credentials.analyticsBaseUrl : credentials.saasBaseUrl,
|
|
147
|
+
path: request.path,
|
|
148
|
+
token: credentials.virtualKey,
|
|
149
|
+
workspaceId,
|
|
150
|
+
qs: request.qs,
|
|
151
|
+
itemIndex,
|
|
152
|
+
};
|
|
153
|
+
return request.host === 'analytics'
|
|
154
|
+
? await requestWithLogPolling(ctx, requestOptions, normalizeAttemptCount(params.requestLogMaxAttempts))
|
|
155
|
+
: await (0, http_1.alephantRequest)(ctx, requestOptions);
|
|
156
|
+
}
|
|
114
157
|
async function executeUsageNode() {
|
|
115
158
|
const items = this.getInputData();
|
|
116
|
-
const credentials = (0, credentials_1.resolveVirtualKeyCredentials)((await this.getCredentials('alephantVirtualKeyApi')));
|
|
117
159
|
const returnData = [];
|
|
118
160
|
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
catch (error) {
|
|
130
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error instanceof Error ? error.message : 'Invalid Alephant Usage input', { itemIndex });
|
|
131
|
-
}
|
|
132
|
-
let workspaceId = request.host === 'analytics'
|
|
133
|
-
? normalizeOptionalString(this.getNodeParameter('workspaceId', itemIndex, '')) ||
|
|
134
|
-
normalizeOptionalString(items[itemIndex]?.json?.workspaceId) ||
|
|
135
|
-
normalizeOptionalString(items[itemIndex]?.json?.workspace_id) ||
|
|
136
|
-
normalizeOptionalString(items[itemIndex]?.json?.xWorkspaceId) ||
|
|
137
|
-
credentials.workspaceId
|
|
138
|
-
: undefined;
|
|
139
|
-
if (request.host === 'analytics' && workspaceId === '') {
|
|
140
|
-
const scope = await (0, http_1.alephantRequest)(this, {
|
|
141
|
-
method: 'GET',
|
|
142
|
-
baseUrl: credentials.saasBaseUrl,
|
|
143
|
-
path: constants_1.ENDPOINTS.cockpitScope,
|
|
144
|
-
token: credentials.virtualKey,
|
|
145
|
-
itemIndex,
|
|
146
|
-
});
|
|
147
|
-
workspaceId = extractWorkspaceIdFromScope(scope);
|
|
148
|
-
}
|
|
149
|
-
if (request.host === 'analytics' && workspaceId === '') {
|
|
150
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Workspace ID is required for request log detail lookups and could not be resolved from Alephant Scope', { itemIndex });
|
|
151
|
-
}
|
|
152
|
-
const requestOptions = {
|
|
153
|
-
method: 'GET',
|
|
154
|
-
baseUrl: request.host === 'analytics' ? credentials.analyticsBaseUrl : credentials.saasBaseUrl,
|
|
155
|
-
path: request.path,
|
|
156
|
-
token: credentials.virtualKey,
|
|
157
|
-
workspaceId,
|
|
158
|
-
qs: request.qs,
|
|
159
|
-
itemIndex,
|
|
160
|
-
};
|
|
161
|
-
const data = request.host === 'analytics'
|
|
162
|
-
? await requestWithLogPolling(this, requestOptions, normalizeAttemptCount(this.getNodeParameter('requestLogMaxAttempts', itemIndex, 6)))
|
|
163
|
-
: await (0, http_1.alephantRequest)(this, requestOptions);
|
|
161
|
+
const data = await runUsageRequest(this, {
|
|
162
|
+
operation: this.getNodeParameter('operation', itemIndex),
|
|
163
|
+
period: this.getNodeParameter('period', itemIndex, '7d'),
|
|
164
|
+
limit: this.getNodeParameter('limit', itemIndex, 50),
|
|
165
|
+
offset: this.getNodeParameter('offset', itemIndex, 0),
|
|
166
|
+
requestLogId: this.getNodeParameter('requestLogId', itemIndex, ''),
|
|
167
|
+
workspaceId: this.getNodeParameter('workspaceId', itemIndex, ''),
|
|
168
|
+
requestLogMaxAttempts: this.getNodeParameter('requestLogMaxAttempts', itemIndex, 6),
|
|
169
|
+
inputJson: items[itemIndex]?.json,
|
|
170
|
+
}, itemIndex);
|
|
164
171
|
returnData.push({
|
|
165
172
|
json: data,
|
|
166
173
|
pairedItem: { item: itemIndex },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alephantai/n8n-nodes-alephant-analytics-ai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "n8n AI tool node for Alephant analytics",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://alephant.io",
|
|
@@ -50,6 +50,9 @@
|
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"n8n-workflow": "*"
|
|
52
52
|
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@langchain/core": "^1.1.46"
|
|
55
|
+
},
|
|
53
56
|
"devDependencies": {
|
|
54
57
|
"n8n-workflow": "*",
|
|
55
58
|
"typescript": "^5.6.3"
|