n8n-nodes-tendem 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/LICENSE +21 -0
- package/README.md +268 -0
- package/dist/credentials/TendemApi.credentials.d.ts +10 -0
- package/dist/credentials/TendemApi.credentials.js +61 -0
- package/dist/credentials/TendemApi.credentials.js.map +1 -0
- package/dist/nodes/Tendem/Tendem.node.d.ts +5 -0
- package/dist/nodes/Tendem/Tendem.node.js +211 -0
- package/dist/nodes/Tendem/Tendem.node.js.map +1 -0
- package/dist/nodes/Tendem/Tendem.node.json +18 -0
- package/dist/nodes/Tendem/descriptions.d.ts +9 -0
- package/dist/nodes/Tendem/descriptions.js +320 -0
- package/dist/nodes/Tendem/descriptions.js.map +1 -0
- package/dist/nodes/Tendem/retry.d.ts +18 -0
- package/dist/nodes/Tendem/retry.js +47 -0
- package/dist/nodes/Tendem/retry.js.map +1 -0
- package/dist/nodes/Tendem/tendem.svg +12 -0
- package/dist/nodes/Tendem/tools.d.ts +34 -0
- package/dist/nodes/Tendem/tools.js +80 -0
- package/dist/nodes/Tendem/tools.js.map +1 -0
- package/dist/nodes/Tendem/transport.d.ts +56 -0
- package/dist/nodes/Tendem/transport.js +265 -0
- package/dist/nodes/Tendem/transport.js.map +1 -0
- package/dist/nodes/Tendem/waitForTask.d.ts +33 -0
- package/dist/nodes/Tendem/waitForTask.js +76 -0
- package/dist/nodes/Tendem/waitForTask.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fileFields = exports.chatFields = exports.taskFields = exports.fileOperations = exports.accountOperations = exports.chatOperations = exports.taskOperations = exports.resourceField = void 0;
|
|
4
|
+
const waitForTask_1 = require("./waitForTask");
|
|
5
|
+
const showFor = (resource, operations) => ({
|
|
6
|
+
show: { resource: [resource], operation: operations },
|
|
7
|
+
});
|
|
8
|
+
exports.resourceField = {
|
|
9
|
+
displayName: 'Resource',
|
|
10
|
+
name: 'resource',
|
|
11
|
+
type: 'options',
|
|
12
|
+
noDataExpression: true,
|
|
13
|
+
default: 'task',
|
|
14
|
+
options: [
|
|
15
|
+
{ name: 'Task', value: 'task' },
|
|
16
|
+
{ name: 'Chat', value: 'chat' },
|
|
17
|
+
{ name: 'Account', value: 'account' },
|
|
18
|
+
{ name: 'File', value: 'file' },
|
|
19
|
+
],
|
|
20
|
+
};
|
|
21
|
+
exports.taskOperations = {
|
|
22
|
+
displayName: 'Operation',
|
|
23
|
+
name: 'operation',
|
|
24
|
+
type: 'options',
|
|
25
|
+
noDataExpression: true,
|
|
26
|
+
default: 'create',
|
|
27
|
+
displayOptions: { show: { resource: ['task'] } },
|
|
28
|
+
options: [
|
|
29
|
+
{
|
|
30
|
+
name: 'Approve (Spends Money)',
|
|
31
|
+
value: 'approve',
|
|
32
|
+
description: 'Approve the scope and quote so a human expert starts work. This charges the Tendem account and requires explicit confirmation.',
|
|
33
|
+
action: 'Approve a task and commit the spend',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'Create',
|
|
37
|
+
value: 'create',
|
|
38
|
+
description: 'Submit a brief. Tendem scopes and prices it — nothing is charged yet.',
|
|
39
|
+
action: 'Create a task',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'Get',
|
|
43
|
+
value: 'get',
|
|
44
|
+
description: 'Read a task snapshot once, including price and approval readiness',
|
|
45
|
+
action: 'Get a task',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'Get Cancel URL',
|
|
49
|
+
value: 'cancel',
|
|
50
|
+
description: 'Get the Tendem UI URL where the user can cancel. This does not cancel anything by itself.',
|
|
51
|
+
action: 'Get the cancel URL for a task',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'Get Contract',
|
|
55
|
+
value: 'getContract',
|
|
56
|
+
description: 'Read the full scope and price the user would be approving',
|
|
57
|
+
action: 'Get the contract for a task',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'Get Result',
|
|
61
|
+
value: 'getResult',
|
|
62
|
+
description: 'Fetch the result markdown plus downloadable file URLs',
|
|
63
|
+
action: 'Get the result of a task',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'List',
|
|
67
|
+
value: 'list',
|
|
68
|
+
description: 'List tasks on the account, useful for recovering task IDs',
|
|
69
|
+
action: 'List tasks',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'Wait for Change',
|
|
73
|
+
value: 'wait',
|
|
74
|
+
description: 'Block until the task needs attention or finishes, using a bounded number of server-side waits',
|
|
75
|
+
action: 'Wait for a task to change',
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
exports.chatOperations = {
|
|
80
|
+
displayName: 'Operation',
|
|
81
|
+
name: 'operation',
|
|
82
|
+
type: 'options',
|
|
83
|
+
noDataExpression: true,
|
|
84
|
+
default: 'read',
|
|
85
|
+
displayOptions: { show: { resource: ['chat'] } },
|
|
86
|
+
options: [
|
|
87
|
+
{
|
|
88
|
+
name: 'Read',
|
|
89
|
+
value: 'read',
|
|
90
|
+
description: 'Read the scoping conversation from a cursor',
|
|
91
|
+
action: 'Read the chat for a task',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'Send',
|
|
95
|
+
value: 'send',
|
|
96
|
+
description: 'Answer a Tendem scoping question, add context, or tell Tendem to start',
|
|
97
|
+
action: 'Send a message to a task',
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
exports.accountOperations = {
|
|
102
|
+
displayName: 'Operation',
|
|
103
|
+
name: 'operation',
|
|
104
|
+
type: 'options',
|
|
105
|
+
noDataExpression: true,
|
|
106
|
+
default: 'get',
|
|
107
|
+
displayOptions: { show: { resource: ['account'] } },
|
|
108
|
+
options: [
|
|
109
|
+
{
|
|
110
|
+
name: 'Get',
|
|
111
|
+
value: 'get',
|
|
112
|
+
description: 'Read the account balance and generic top-up URL',
|
|
113
|
+
action: 'Get the account',
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
};
|
|
117
|
+
exports.fileOperations = {
|
|
118
|
+
displayName: 'Operation',
|
|
119
|
+
name: 'operation',
|
|
120
|
+
type: 'options',
|
|
121
|
+
noDataExpression: true,
|
|
122
|
+
default: 'getUploadUrl',
|
|
123
|
+
displayOptions: { show: { resource: ['file'] } },
|
|
124
|
+
options: [
|
|
125
|
+
{
|
|
126
|
+
name: 'Get Upload URL',
|
|
127
|
+
value: 'getUploadUrl',
|
|
128
|
+
description: 'Get a short-lived folder URL for attaching input files to a task, then name them in a chat message',
|
|
129
|
+
action: 'Get a file upload URL',
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
};
|
|
133
|
+
exports.taskFields = [
|
|
134
|
+
{
|
|
135
|
+
displayName: 'Name',
|
|
136
|
+
name: 'taskName',
|
|
137
|
+
type: 'string',
|
|
138
|
+
default: '',
|
|
139
|
+
required: true,
|
|
140
|
+
displayOptions: showFor('task', ['create']),
|
|
141
|
+
description: 'Short task name shown in Tendem lists and UIs (max 120 characters)',
|
|
142
|
+
placeholder: 'Competitor research for EU freight brokerage',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
displayName: 'Description',
|
|
146
|
+
name: 'description',
|
|
147
|
+
type: 'string',
|
|
148
|
+
typeOptions: { rows: 5 },
|
|
149
|
+
default: '',
|
|
150
|
+
required: true,
|
|
151
|
+
displayOptions: showFor('task', ['create']),
|
|
152
|
+
description: "The actual request, in plain language — posted as the first chat message. Pass the requester's own words through verbatim; Tendem's orchestrator does the scoping and asks follow-up questions over chat. Tendem declines data-scraping work by policy.",
|
|
153
|
+
placeholder: 'Research the top 5 competitors in EU freight brokerage and summarise their pricing models in a one-page brief',
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
displayName: 'Conversation ID',
|
|
157
|
+
name: 'conversationId',
|
|
158
|
+
type: 'string',
|
|
159
|
+
default: '',
|
|
160
|
+
displayOptions: showFor('task', ['create']),
|
|
161
|
+
description: 'Optional stable identifier that lets Tendem correlate several tasks from one conversation',
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
displayName: 'Task ID',
|
|
165
|
+
name: 'taskId',
|
|
166
|
+
type: 'string',
|
|
167
|
+
default: '',
|
|
168
|
+
required: true,
|
|
169
|
+
displayOptions: showFor('task', [
|
|
170
|
+
'get',
|
|
171
|
+
'getContract',
|
|
172
|
+
'approve',
|
|
173
|
+
'cancel',
|
|
174
|
+
'getResult',
|
|
175
|
+
'wait',
|
|
176
|
+
]),
|
|
177
|
+
description: 'Task UUID returned by the Create operation',
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
displayName: 'This charges the Tendem account for real. Read the scope and price first with "Get Contract", put a human decision in front of this node, and pass the price through below so the confirmation names what is being bought.',
|
|
181
|
+
name: 'approvalNotice',
|
|
182
|
+
type: 'notice',
|
|
183
|
+
default: '',
|
|
184
|
+
displayOptions: showFor('task', ['approve']),
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
displayName: 'Name',
|
|
188
|
+
name: 'taskName',
|
|
189
|
+
type: 'string',
|
|
190
|
+
default: '',
|
|
191
|
+
required: true,
|
|
192
|
+
displayOptions: showFor('task', ['approve', 'cancel']),
|
|
193
|
+
description: 'Task name, passed through from Get Task. Tendem uses it in its guidance text.',
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
displayName: 'Price',
|
|
197
|
+
name: 'price',
|
|
198
|
+
type: 'string',
|
|
199
|
+
default: '',
|
|
200
|
+
required: true,
|
|
201
|
+
displayOptions: showFor('task', ['approve']),
|
|
202
|
+
description: 'The formatted price from Get Task or Get Contract, e.g. "$40.00". Required by Tendem, and it means the amount being committed has to have been read before this node can approve it.',
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
displayName: 'Confirm Spend',
|
|
206
|
+
name: 'confirmSpend',
|
|
207
|
+
type: 'boolean',
|
|
208
|
+
default: false,
|
|
209
|
+
required: true,
|
|
210
|
+
displayOptions: showFor('task', ['approve']),
|
|
211
|
+
description: 'Whether to actually commit the spend. The node refuses to approve while this is off, so approval cannot happen by accident. Drive it from an expression if a human decision upstream should decide.',
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
displayName: 'Wait for Change (Seconds)',
|
|
215
|
+
name: 'waitForChangeSeconds',
|
|
216
|
+
type: 'number',
|
|
217
|
+
default: waitForTask_1.DEFAULT_WAIT_FOR_CHANGE_SECONDS,
|
|
218
|
+
typeOptions: {
|
|
219
|
+
minValue: waitForTask_1.MIN_WAIT_FOR_CHANGE_SECONDS,
|
|
220
|
+
maxValue: waitForTask_1.MAX_WAIT_FOR_CHANGE_SECONDS,
|
|
221
|
+
},
|
|
222
|
+
displayOptions: showFor('task', ['wait']),
|
|
223
|
+
description: 'How long the Tendem server holds each request open waiting for a change (max 30, the API limit). The wait happens server-side, so this is not a client polling interval.',
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
displayName: 'Max Rounds',
|
|
227
|
+
name: 'maxRounds',
|
|
228
|
+
type: 'number',
|
|
229
|
+
default: waitForTask_1.DEFAULT_MAX_ROUNDS,
|
|
230
|
+
typeOptions: { minValue: waitForTask_1.MIN_MAX_ROUNDS, maxValue: waitForTask_1.MAX_MAX_ROUNDS },
|
|
231
|
+
displayOptions: showFor('task', ['wait']),
|
|
232
|
+
description: 'Hard cap on how many server-side waits to perform. When the budget runs out the node emits the latest snapshot with "tendemWait.timedOut" set to true rather than looping forever — branch on it and re-enter the wait later.',
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
displayName: 'Limit',
|
|
236
|
+
name: 'limit',
|
|
237
|
+
type: 'number',
|
|
238
|
+
default: 50,
|
|
239
|
+
typeOptions: { minValue: 1, maxValue: 100 },
|
|
240
|
+
displayOptions: showFor('task', ['list']),
|
|
241
|
+
description: 'Max number of results to return',
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
displayName: 'Offset',
|
|
245
|
+
name: 'offset',
|
|
246
|
+
type: 'number',
|
|
247
|
+
default: 0,
|
|
248
|
+
typeOptions: { minValue: 0 },
|
|
249
|
+
displayOptions: showFor('task', ['list']),
|
|
250
|
+
description: 'Number of tasks to skip',
|
|
251
|
+
},
|
|
252
|
+
];
|
|
253
|
+
exports.chatFields = [
|
|
254
|
+
{
|
|
255
|
+
displayName: 'Task ID',
|
|
256
|
+
name: 'taskId',
|
|
257
|
+
type: 'string',
|
|
258
|
+
default: '',
|
|
259
|
+
required: true,
|
|
260
|
+
displayOptions: showFor('chat', ['read', 'send']),
|
|
261
|
+
description: 'Task UUID returned by the Create operation',
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
displayName: 'From Offset',
|
|
265
|
+
name: 'fromOffset',
|
|
266
|
+
type: 'number',
|
|
267
|
+
default: 0,
|
|
268
|
+
typeOptions: { minValue: 0 },
|
|
269
|
+
displayOptions: showFor('chat', ['read']),
|
|
270
|
+
description: 'Offset of the first message to return. 0 returns the full history.',
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
displayName: 'Text',
|
|
274
|
+
name: 'text',
|
|
275
|
+
type: 'string',
|
|
276
|
+
typeOptions: { rows: 4 },
|
|
277
|
+
default: '',
|
|
278
|
+
required: true,
|
|
279
|
+
displayOptions: showFor('chat', ['send']),
|
|
280
|
+
description: 'Message text to send to the Tendem orchestrator',
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
displayName: 'Resolve Offset Automatically',
|
|
284
|
+
name: 'autoOffset',
|
|
285
|
+
type: 'boolean',
|
|
286
|
+
default: true,
|
|
287
|
+
displayOptions: showFor('chat', ['send']),
|
|
288
|
+
description: 'Whether to read the chat first and send at the live offset, re-sending once if Tendem posts new content concurrently. Turn off to thread "last_seen_offset" through the workflow by hand.',
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
displayName: 'Last Seen Offset',
|
|
292
|
+
name: 'lastSeenOffset',
|
|
293
|
+
type: 'number',
|
|
294
|
+
default: 0,
|
|
295
|
+
typeOptions: { minValue: 0 },
|
|
296
|
+
displayOptions: {
|
|
297
|
+
show: { resource: ['chat'], operation: ['send'], autoOffset: [false] },
|
|
298
|
+
},
|
|
299
|
+
description: 'The "last_seen_offset" from the previous Create, Send, or Read call. 0 for a brand-new task. If Tendem posted new content first, the response comes back with response_type "race" and the message is not delivered — re-send with the new offset.',
|
|
300
|
+
},
|
|
301
|
+
];
|
|
302
|
+
exports.fileFields = [
|
|
303
|
+
{
|
|
304
|
+
displayName: 'Task ID',
|
|
305
|
+
name: 'taskId',
|
|
306
|
+
type: 'string',
|
|
307
|
+
default: '',
|
|
308
|
+
required: true,
|
|
309
|
+
displayOptions: showFor('file', ['getUploadUrl']),
|
|
310
|
+
description: 'Task UUID to attach files to. Upload only works after the task exists, so create the task first.',
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
displayName: 'The returned "upload_url" is a folder URL on the ".dfs.core.windows.net" host. For each file: swap that host to ".blob.core.windows.net", append the file name to the path before the query string — <base>/<filename>?<query> — and PUT the raw bytes with the header "x-ms-blob-type: BlockBlob". A PUT to the URL exactly as returned fails with HTTP 400. Then use Chat → Send to name the files you uploaded, or Tendem will keep waiting for them.',
|
|
314
|
+
name: 'uploadNotice',
|
|
315
|
+
type: 'notice',
|
|
316
|
+
default: '',
|
|
317
|
+
displayOptions: showFor('file', ['getUploadUrl']),
|
|
318
|
+
},
|
|
319
|
+
];
|
|
320
|
+
//# sourceMappingURL=descriptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"descriptions.js","sourceRoot":"","sources":["../../../nodes/Tendem/descriptions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { IDataObject } from 'n8n-workflow';
|
|
2
|
+
import { type ToolCaller } from './tools';
|
|
3
|
+
export declare const TRANSIENT_ERROR_CODE = "TEMPORARILY_UNAVAILABLE";
|
|
4
|
+
export declare const MAX_TRANSIENT_RETRIES = 5;
|
|
5
|
+
export declare const TRANSIENT_BACKOFF_BASE_MS = 2000;
|
|
6
|
+
export declare const TRANSIENT_BACKOFF_MAX_MS = 60000;
|
|
7
|
+
export declare function isTransientError(error: unknown): boolean;
|
|
8
|
+
export declare function transientBackoffMs(attempt: number): number;
|
|
9
|
+
export interface RetryDeps {
|
|
10
|
+
sleep(ms: number): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export declare class RetryingToolCaller implements ToolCaller {
|
|
13
|
+
private readonly inner;
|
|
14
|
+
private readonly deps;
|
|
15
|
+
private readonly maxRetries;
|
|
16
|
+
constructor(inner: ToolCaller, deps: RetryDeps, maxRetries?: number);
|
|
17
|
+
callTool(name: string, args?: IDataObject): Promise<IDataObject>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RetryingToolCaller = exports.TRANSIENT_BACKOFF_MAX_MS = exports.TRANSIENT_BACKOFF_BASE_MS = exports.MAX_TRANSIENT_RETRIES = exports.TRANSIENT_ERROR_CODE = void 0;
|
|
4
|
+
exports.isTransientError = isTransientError;
|
|
5
|
+
exports.transientBackoffMs = transientBackoffMs;
|
|
6
|
+
const transport_1 = require("./transport");
|
|
7
|
+
const tools_1 = require("./tools");
|
|
8
|
+
exports.TRANSIENT_ERROR_CODE = 'TEMPORARILY_UNAVAILABLE';
|
|
9
|
+
exports.MAX_TRANSIENT_RETRIES = 5;
|
|
10
|
+
exports.TRANSIENT_BACKOFF_BASE_MS = 2000;
|
|
11
|
+
exports.TRANSIENT_BACKOFF_MAX_MS = 60000;
|
|
12
|
+
const TRANSIENT_HTTP_STATUSES = new Set([429, 500, 502, 503, 504]);
|
|
13
|
+
function isTransientError(error) {
|
|
14
|
+
if (error instanceof transport_1.McpError) {
|
|
15
|
+
if (error.httpStatus !== undefined)
|
|
16
|
+
return TRANSIENT_HTTP_STATUSES.has(error.httpStatus);
|
|
17
|
+
return error.message.includes(exports.TRANSIENT_ERROR_CODE);
|
|
18
|
+
}
|
|
19
|
+
return error instanceof Error;
|
|
20
|
+
}
|
|
21
|
+
function transientBackoffMs(attempt) {
|
|
22
|
+
return Math.min(exports.TRANSIENT_BACKOFF_BASE_MS * 2 ** attempt, exports.TRANSIENT_BACKOFF_MAX_MS);
|
|
23
|
+
}
|
|
24
|
+
class RetryingToolCaller {
|
|
25
|
+
constructor(inner, deps, maxRetries = exports.MAX_TRANSIENT_RETRIES) {
|
|
26
|
+
this.inner = inner;
|
|
27
|
+
this.deps = deps;
|
|
28
|
+
this.maxRetries = maxRetries;
|
|
29
|
+
}
|
|
30
|
+
async callTool(name, args = {}) {
|
|
31
|
+
if (!tools_1.IDEMPOTENT_TOOLS.includes(name)) {
|
|
32
|
+
return await this.inner.callTool(name, args);
|
|
33
|
+
}
|
|
34
|
+
let attempt = 0;
|
|
35
|
+
for (;;) {
|
|
36
|
+
const outcome = await this.inner.callTool(name, args).then((value) => ({ ok: true, value }), (error) => ({ ok: false, error }));
|
|
37
|
+
if (outcome.ok)
|
|
38
|
+
return outcome.value;
|
|
39
|
+
if (!isTransientError(outcome.error) || attempt >= this.maxRetries)
|
|
40
|
+
throw outcome.error;
|
|
41
|
+
await this.deps.sleep(transientBackoffMs(attempt));
|
|
42
|
+
attempt += 1;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.RetryingToolCaller = RetryingToolCaller;
|
|
47
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../../nodes/Tendem/retry.ts"],"names":[],"mappings":";;;AAkCA,4CAMC;AAED,gDAEC;AA1CD,2CAAuC;AACvC,mCAA4D;AAc/C,QAAA,oBAAoB,GAAG,yBAAyB,CAAC;AAGjD,QAAA,qBAAqB,GAAG,CAAC,CAAC;AAE1B,QAAA,yBAAyB,GAAG,IAAK,CAAC;AAClC,QAAA,wBAAwB,GAAG,KAAM,CAAC;AAG/C,MAAM,uBAAuB,GAAwB,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAQxF,SAAgB,gBAAgB,CAAC,KAAc;IAC9C,IAAI,KAAK,YAAY,oBAAQ,EAAE,CAAC;QAC/B,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;YAAE,OAAO,uBAAuB,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACzF,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,4BAAoB,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,KAAK,YAAY,KAAK,CAAC;AAC/B,CAAC;AAED,SAAgB,kBAAkB,CAAC,OAAe;IACjD,OAAO,IAAI,CAAC,GAAG,CAAC,iCAAyB,GAAG,CAAC,IAAI,OAAO,EAAE,gCAAwB,CAAC,CAAC;AACrF,CAAC;AAMD,MAAa,kBAAkB;IAC9B,YACkB,KAAiB,EACjB,IAAe,EACf,aAAqB,6BAAqB;QAF1C,UAAK,GAAL,KAAK,CAAY;QACjB,SAAI,GAAJ,IAAI,CAAW;QACf,eAAU,GAAV,UAAU,CAAgC;IACzD,CAAC;IAEJ,KAAK,CAAC,QAAQ,CAAC,IAAY,EAAE,OAAoB,EAAE;QAClD,IAAI,CAAC,wBAAgB,CAAC,QAAQ,CAAC,IAAyC,CAAC,EAAE,CAAC;YAC3E,OAAO,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC9C,CAAC;QAED,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,SAAS,CAAC;YAGT,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CACzD,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAa,EAAE,KAAK,EAAE,CAAC,EACzC,CAAC,KAAc,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAc,EAAE,KAAK,EAAE,CAAC,CACnD,CAAC;YAEF,IAAI,OAAO,CAAC,EAAE;gBAAE,OAAO,OAAO,CAAC,KAAK,CAAC;YACrC,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,OAAO,IAAI,IAAI,CAAC,UAAU;gBAAE,MAAM,OAAO,CAAC,KAAK,CAAC;YAExF,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC,CAAC;QACd,CAAC;IACF,CAAC;CACD;AA5BD,gDA4BC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<svg width="495" height="495" viewBox="0 0 495 495" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<g clip-path="url(#clip0_6332_12817)">
|
|
3
|
+
<rect width="495" height="495" rx="110" fill="#323224"/>
|
|
4
|
+
<rect x="103.125" y="78.375" width="338.25" height="338.25" fill="white"/>
|
|
5
|
+
<path d="M427.79 0H67.2101C30.0918 0 0 30.0918 0 67.2101V427.79C0 464.908 30.0918 495 67.2101 495H427.79C464.908 495 495 464.908 495 427.79V67.2101C495 30.0918 464.908 0 427.79 0ZM395.414 189.23C395.414 208.359 369.187 213.738 361.657 196.154C354.961 180.518 332.176 182.547 328.349 199.12L288.583 371.326C286.74 379.304 279.635 384.956 271.445 384.956H154.044C139.853 384.956 131.505 369.017 139.583 357.352L220.177 240.992C231.638 224.441 210.816 204.734 194.922 217.089L148.85 252.906C137.297 261.888 120.464 253.655 120.464 239.019V127.017C120.464 113.664 135.184 105.553 146.472 112.686L272.593 192.376C280.001 197.058 289.727 195.571 295.399 188.888L355.483 118.099C369.131 102.019 395.414 111.671 395.414 132.76V189.224V189.23Z" fill="#323224"/>
|
|
6
|
+
</g>
|
|
7
|
+
<defs>
|
|
8
|
+
<clipPath id="clip0_6332_12817">
|
|
9
|
+
<rect width="495" height="495" rx="110" fill="white"/>
|
|
10
|
+
</clipPath>
|
|
11
|
+
</defs>
|
|
12
|
+
</svg>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { IDataObject } from 'n8n-workflow';
|
|
2
|
+
export declare const TENDEM_TOOLS: {
|
|
3
|
+
readonly CREATE_TASK: "create_task";
|
|
4
|
+
readonly GET_TASK: "get_task";
|
|
5
|
+
readonly GET_CONTRACT: "get_contract";
|
|
6
|
+
readonly APPROVE_TASK: "approve_task";
|
|
7
|
+
readonly CANCEL_TASK: "cancel_task";
|
|
8
|
+
readonly GET_TASK_RESULT: "get_task_result";
|
|
9
|
+
readonly LIST_TASKS: "list_tasks";
|
|
10
|
+
readonly READ_CHAT: "read_chat";
|
|
11
|
+
readonly SEND_MESSAGE: "send_message";
|
|
12
|
+
readonly GET_ACCOUNT: "get_account";
|
|
13
|
+
readonly GET_FILE_UPLOAD_URL: "get_file_upload_url";
|
|
14
|
+
};
|
|
15
|
+
export type TendemToolName = (typeof TENDEM_TOOLS)[keyof typeof TENDEM_TOOLS];
|
|
16
|
+
export declare const SPEND_COMMITTING_TOOLS: readonly TendemToolName[];
|
|
17
|
+
export declare const SPEND_OPERATION_KEY = "task:approve";
|
|
18
|
+
export declare const IDEMPOTENT_TOOLS: readonly TendemToolName[];
|
|
19
|
+
export declare const OPERATION_TOOL_ALLOWLIST: Readonly<Record<string, readonly TendemToolName[]>>;
|
|
20
|
+
export interface ToolCaller {
|
|
21
|
+
callTool(name: string, args?: IDataObject): Promise<IDataObject>;
|
|
22
|
+
}
|
|
23
|
+
export declare class ToolNotPermittedError extends Error {
|
|
24
|
+
constructor(message: string);
|
|
25
|
+
}
|
|
26
|
+
export declare class GuardedToolCaller implements ToolCaller {
|
|
27
|
+
private readonly inner;
|
|
28
|
+
private readonly operationKey;
|
|
29
|
+
private readonly allowed;
|
|
30
|
+
constructor(inner: ToolCaller, operationKey: string, allowed: readonly string[]);
|
|
31
|
+
callTool(name: string, args?: IDataObject): Promise<IDataObject>;
|
|
32
|
+
}
|
|
33
|
+
export declare function operationKey(resource: string, operation: string): string;
|
|
34
|
+
export declare function guardFor(inner: ToolCaller, key: string): GuardedToolCaller;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GuardedToolCaller = exports.ToolNotPermittedError = exports.OPERATION_TOOL_ALLOWLIST = exports.IDEMPOTENT_TOOLS = exports.SPEND_OPERATION_KEY = exports.SPEND_COMMITTING_TOOLS = exports.TENDEM_TOOLS = void 0;
|
|
4
|
+
exports.operationKey = operationKey;
|
|
5
|
+
exports.guardFor = guardFor;
|
|
6
|
+
exports.TENDEM_TOOLS = {
|
|
7
|
+
CREATE_TASK: 'create_task',
|
|
8
|
+
GET_TASK: 'get_task',
|
|
9
|
+
GET_CONTRACT: 'get_contract',
|
|
10
|
+
APPROVE_TASK: 'approve_task',
|
|
11
|
+
CANCEL_TASK: 'cancel_task',
|
|
12
|
+
GET_TASK_RESULT: 'get_task_result',
|
|
13
|
+
LIST_TASKS: 'list_tasks',
|
|
14
|
+
READ_CHAT: 'read_chat',
|
|
15
|
+
SEND_MESSAGE: 'send_message',
|
|
16
|
+
GET_ACCOUNT: 'get_account',
|
|
17
|
+
GET_FILE_UPLOAD_URL: 'get_file_upload_url',
|
|
18
|
+
};
|
|
19
|
+
exports.SPEND_COMMITTING_TOOLS = [exports.TENDEM_TOOLS.APPROVE_TASK];
|
|
20
|
+
exports.SPEND_OPERATION_KEY = 'task:approve';
|
|
21
|
+
exports.IDEMPOTENT_TOOLS = [
|
|
22
|
+
exports.TENDEM_TOOLS.GET_TASK,
|
|
23
|
+
exports.TENDEM_TOOLS.GET_CONTRACT,
|
|
24
|
+
exports.TENDEM_TOOLS.CANCEL_TASK,
|
|
25
|
+
exports.TENDEM_TOOLS.GET_TASK_RESULT,
|
|
26
|
+
exports.TENDEM_TOOLS.LIST_TASKS,
|
|
27
|
+
exports.TENDEM_TOOLS.READ_CHAT,
|
|
28
|
+
exports.TENDEM_TOOLS.GET_ACCOUNT,
|
|
29
|
+
exports.TENDEM_TOOLS.GET_FILE_UPLOAD_URL,
|
|
30
|
+
];
|
|
31
|
+
exports.OPERATION_TOOL_ALLOWLIST = {
|
|
32
|
+
'task:create': [exports.TENDEM_TOOLS.CREATE_TASK],
|
|
33
|
+
'task:get': [exports.TENDEM_TOOLS.GET_TASK],
|
|
34
|
+
'task:wait': [exports.TENDEM_TOOLS.GET_TASK],
|
|
35
|
+
'task:getContract': [exports.TENDEM_TOOLS.GET_CONTRACT],
|
|
36
|
+
'task:approve': [exports.TENDEM_TOOLS.APPROVE_TASK],
|
|
37
|
+
'task:cancel': [exports.TENDEM_TOOLS.CANCEL_TASK],
|
|
38
|
+
'task:getResult': [exports.TENDEM_TOOLS.GET_TASK_RESULT],
|
|
39
|
+
'task:list': [exports.TENDEM_TOOLS.LIST_TASKS],
|
|
40
|
+
'chat:read': [exports.TENDEM_TOOLS.READ_CHAT],
|
|
41
|
+
'chat:send': [exports.TENDEM_TOOLS.SEND_MESSAGE, exports.TENDEM_TOOLS.READ_CHAT],
|
|
42
|
+
'account:get': [exports.TENDEM_TOOLS.GET_ACCOUNT],
|
|
43
|
+
'file:getUploadUrl': [exports.TENDEM_TOOLS.GET_FILE_UPLOAD_URL],
|
|
44
|
+
};
|
|
45
|
+
class ToolNotPermittedError extends Error {
|
|
46
|
+
constructor(message) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.name = 'ToolNotPermittedError';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.ToolNotPermittedError = ToolNotPermittedError;
|
|
52
|
+
class GuardedToolCaller {
|
|
53
|
+
constructor(inner, operationKey, allowed) {
|
|
54
|
+
this.inner = inner;
|
|
55
|
+
this.operationKey = operationKey;
|
|
56
|
+
this.allowed = allowed;
|
|
57
|
+
}
|
|
58
|
+
async callTool(name, args = {}) {
|
|
59
|
+
if (!this.allowed.includes(name)) {
|
|
60
|
+
throw new ToolNotPermittedError(`The Tendem "${this.operationKey}" operation is not permitted to call "${name}". ` +
|
|
61
|
+
`Permitted: ${this.allowed.join(', ')}.` +
|
|
62
|
+
(exports.SPEND_COMMITTING_TOOLS.includes(name)
|
|
63
|
+
? ` "${name}" spends real money and is only reachable from the dedicated "Approve Task" operation.`
|
|
64
|
+
: ''));
|
|
65
|
+
}
|
|
66
|
+
return await this.inner.callTool(name, args);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.GuardedToolCaller = GuardedToolCaller;
|
|
70
|
+
function operationKey(resource, operation) {
|
|
71
|
+
return `${resource}:${operation}`;
|
|
72
|
+
}
|
|
73
|
+
function guardFor(inner, key) {
|
|
74
|
+
const allowed = exports.OPERATION_TOOL_ALLOWLIST[key];
|
|
75
|
+
if (allowed === undefined) {
|
|
76
|
+
throw new ToolNotPermittedError(`Unknown Tendem operation "${key}"`);
|
|
77
|
+
}
|
|
78
|
+
return new GuardedToolCaller(inner, key, allowed);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../nodes/Tendem/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { IDataObject } from 'n8n-workflow';
|
|
2
|
+
export declare const MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
3
|
+
export declare const MCP_CLIENT_NAME = "n8n-nodes-tendem";
|
|
4
|
+
export declare const MCP_CLIENT_VERSION = "0.1.0";
|
|
5
|
+
export declare const TENDEM_DEFAULT_ENDPOINT = "https://mcp.tendem.ai/mcp?utm_hash=83dad40a52";
|
|
6
|
+
export interface McpHttpRequestOptions {
|
|
7
|
+
method: 'POST';
|
|
8
|
+
url: string;
|
|
9
|
+
headers: Record<string, string>;
|
|
10
|
+
body: IDataObject;
|
|
11
|
+
json: boolean;
|
|
12
|
+
returnFullResponse: true;
|
|
13
|
+
ignoreHttpStatusErrors: true;
|
|
14
|
+
timeout: number;
|
|
15
|
+
}
|
|
16
|
+
export interface McpHttpResponse {
|
|
17
|
+
statusCode: number;
|
|
18
|
+
headers?: Record<string, unknown>;
|
|
19
|
+
body?: unknown;
|
|
20
|
+
}
|
|
21
|
+
export type McpHttpRequester = (options: McpHttpRequestOptions) => Promise<McpHttpResponse>;
|
|
22
|
+
export declare class McpError extends Error {
|
|
23
|
+
readonly code?: number;
|
|
24
|
+
readonly data?: unknown;
|
|
25
|
+
readonly httpStatus?: number;
|
|
26
|
+
constructor(message: string, code?: number, data?: unknown, httpStatus?: number);
|
|
27
|
+
}
|
|
28
|
+
export declare class McpSessionExpiredError extends McpError {
|
|
29
|
+
constructor();
|
|
30
|
+
}
|
|
31
|
+
export declare function extractJsonRpcMessage(body: unknown): IDataObject | undefined;
|
|
32
|
+
export declare function toolResultIsError(result: unknown): boolean;
|
|
33
|
+
export declare function unwrapToolResult(result: unknown): IDataObject;
|
|
34
|
+
export interface McpSessionOptions {
|
|
35
|
+
endpoint: string;
|
|
36
|
+
timeoutMs?: number;
|
|
37
|
+
}
|
|
38
|
+
export declare class McpSession {
|
|
39
|
+
private readonly request;
|
|
40
|
+
private readonly endpoint;
|
|
41
|
+
private readonly timeoutMs;
|
|
42
|
+
private sessionId?;
|
|
43
|
+
private protocolVersion;
|
|
44
|
+
private nextId;
|
|
45
|
+
private handshake?;
|
|
46
|
+
constructor(request: McpHttpRequester, options: McpSessionOptions);
|
|
47
|
+
callTool(name: string, args?: IDataObject): Promise<IDataObject>;
|
|
48
|
+
private reset;
|
|
49
|
+
private invokeTool;
|
|
50
|
+
private ensureInitialized;
|
|
51
|
+
private performHandshake;
|
|
52
|
+
private rpc;
|
|
53
|
+
private post;
|
|
54
|
+
private buildHeaders;
|
|
55
|
+
private handleResponse;
|
|
56
|
+
}
|