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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Toloka AI BV
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,268 @@
1
+ # n8n-nodes-tendem
2
+
3
+ An [n8n](https://n8n.io) community node for [Tendem](https://tendem.ai) — a hybrid
4
+ AI + human task service. You submit a task in plain English, Tendem's orchestrator
5
+ scopes it in a chat and quotes a transparent price, and once a **human** approves
6
+ the spend, a vetted expert executes it and returns verified results as markdown
7
+ plus files.
8
+
9
+ Use it when a workflow hits work an automation can't reliably nail: research and
10
+ competitive analysis, copywriting and editing, design review, data cleaning, list
11
+ building, anything needing real judgement. Don't use it for quick
12
+ general-knowledge lookups, and note that Tendem declines data-scraping work by
13
+ policy.
14
+
15
+ - [Installation](#installation)
16
+ - [Credentials](#credentials)
17
+ - [Operations](#operations)
18
+ - [Approving a task spends real money](#approving-a-task-spends-real-money)
19
+ - [Worked example](#worked-example-research-brief-end-to-end)
20
+ - [Polling without a busy loop](#polling-without-a-busy-loop)
21
+ - [Attaching input files](#attaching-input-files)
22
+ - [Compatibility](#compatibility)
23
+
24
+ ## Installation
25
+
26
+ Go to **Settings → Community nodes → Install**, enter `n8n-nodes-tendem`, accept
27
+ the risk prompt, and install. A **Tendem** node appears in the node panel.
28
+
29
+ Other setups are covered in n8n's own guide: [Installing community
30
+ nodes](https://docs.n8n.io/integrations/community-nodes/installation/).
31
+
32
+ ## Credentials
33
+
34
+ The node talks to Tendem's hosted MCP server over streamable HTTP. Authentication
35
+ is an **API key**, sent as `Authorization: ApiKey <token>`.
36
+
37
+ 1. Sign in at [agent.tendem.ai](https://agent.tendem.ai).
38
+ 2. Go to [agent.tendem.ai/mcp](https://agent.tendem.ai/mcp), open the **Agent
39
+ builders** tab, and click **Generate API key**.
40
+ 3. In n8n: **Credentials → New → Tendem API**, paste the token, save.
41
+
42
+ Use n8n's **Test** button on the credential — it performs a real MCP `initialize`
43
+ handshake against the endpoint, so a bad key fails immediately rather than at the
44
+ first workflow run.
45
+
46
+ | Field | Default | Notes |
47
+ |---|---|---|
48
+ | API Key | — | Required. Stored encrypted by n8n; never put it in a node parameter or an HTTP Request node. |
49
+ | MCP Endpoint | `https://mcp.tendem.ai/mcp?utm_hash=83dad40a52` | Overridable, but only change it to target a non-production Tendem deployment. The `utm_hash` is n8n channel attribution. |
50
+
51
+ Tendem also supports interactive OAuth, which is what the Claude Code / Cursor /
52
+ Gemini plugins use. n8n workflows run unattended, so this node deliberately does
53
+ API keys only.
54
+
55
+ ## Operations
56
+
57
+ | Resource | Operation | Tendem tool | Spends money |
58
+ |---|---|---|---|
59
+ | Task | Create | `create_task` | no |
60
+ | Task | Get | `get_task` | no |
61
+ | Task | Get Contract | `get_contract` | no |
62
+ | Task | **Approve (Spends Money)** | `approve_task` | **yes** |
63
+ | Task | Get Cancel URL | `cancel_task` | no |
64
+ | Task | Get Result | `get_task_result` | no |
65
+ | Task | List | `list_tasks` | no |
66
+ | Task | Wait for Change | `get_task` (long-poll) | no |
67
+ | Chat | Read | `read_chat` | no |
68
+ | Chat | Send | `send_message` | no |
69
+ | Account | Get | `get_account` | no |
70
+ | File | Get Upload URL | `get_file_upload_url` | no |
71
+
72
+ Every response is passed through as JSON on the item, including Tendem's guidance
73
+ envelope — `next_action`, `poll_after_seconds`, `poll_timeout_seconds`,
74
+ `guidance`. **Branch on `next_action`, not on the raw `status`**; Tendem treats it
75
+ as authoritative. The statuses you'll see are `ACTING`, `LISTENING`,
76
+ `NEEDS_REPAIR`, `CLOSED` (terminal, but the result is still fetchable) and
77
+ `DELETED`.
78
+
79
+ ### Note on Get Cancel URL
80
+
81
+ `cancel_task` does **not** cancel anything. It returns a Tendem UI URL where a
82
+ person can cancel. Send them there.
83
+
84
+ ## Approving a task spends real money
85
+
86
+ Approval charges the Tendem account, so the node treats it as a distinct,
87
+ deliberate act rather than a step that can happen on the way to something else.
88
+ Four things stand in the way, and they are structural, not documentation:
89
+
90
+ 1. **Approval is its own operation.** `approve_task` is reachable only from
91
+ Task → Approve. A workflow author has to add that node on purpose.
92
+ 2. **Per-operation capability guard.** Each operation executes against an
93
+ allowlist naming the single Tendem tool it may call. Approve is the only row
94
+ containing `approve_task`; every other operation is refused *before* any HTTP
95
+ request is made. Creating a task, polling one, or reading its chat cannot
96
+ approve it even if the code above them were wrong.
97
+ 3. **Confirm Spend must be on.** The Approve operation refuses while the
98
+ **Confirm Spend** toggle is off. Drive it from an expression if a human
99
+ decision upstream — an n8n Wait-for-form, a Slack approval, an email gate —
100
+ should decide. It is evaluated per item, so confirming one item never
101
+ approves another.
102
+ 4. **A price must be supplied.** Approve requires the quoted price, which means
103
+ the amount being committed had to be read before it could be committed.
104
+
105
+ The node also never tops up and never retries. Insufficient balance comes back as
106
+ **data**, not an exception, so you can route on it:
107
+
108
+ ```
109
+ { "approved": false, "spendBlocked": true, "topupUrl": "https://…", "reason": "insufficient_balance" }
110
+ ```
111
+
112
+ Send `topupUrl` to the user. That link is task-bound: paying it tops up *and*
113
+ auto-approves this task, so don't call Approve again afterwards.
114
+
115
+ On success you get `approved: true`, `spendBlocked: false`, `topupUrl: null`.
116
+
117
+ ### Why the node isn't available as an AI Agent tool
118
+
119
+ n8n's `usableAsTool` is all-or-nothing per node — there is no form of it that
120
+ exposes some operations and withholds others. Turning it on would hand a model
121
+ the Approve operation. Spend is a workflow author's decision, so this node stays
122
+ off the AI tool surface. An agent that needs the read-only parts can talk to the
123
+ [Tendem MCP server](https://github.com/Toloka/tendem-mcp) directly, where the
124
+ host application owns the approval gate.
125
+
126
+ ## Worked example: research brief, end to end
127
+
128
+ A workflow that submits a brief, surfaces the quote to a human, and only then
129
+ spends. Nine nodes:
130
+
131
+ ```
132
+ Manual Trigger
133
+ → Tendem: Task → Create
134
+ → Tendem: Task → Wait for Change (until the quote is ready)
135
+ → Tendem: Task → Get Contract (scope + price)
136
+ → Slack / Email: send the scope and price to a human
137
+ → Wait for approval (n8n Wait node with a form / webhook resume)
138
+ → IF: did the human approve?
139
+ true → Tendem: Task → Approve (Confirm Spend = the human's answer)
140
+ → Tendem: Task → Wait for Change (until the work is done)
141
+ → Tendem: Task → Get Result
142
+ false → Tendem: Task → Get Cancel URL (and send it to the human)
143
+ ```
144
+
145
+ **1. Task → Create.** Pass the requester's own words through verbatim. Don't
146
+ pre-interrogate them and don't rewrite the brief — Tendem's orchestrator does the
147
+ scoping and asks follow-up questions over chat.
148
+
149
+ | Parameter | Value |
150
+ |---|---|
151
+ | Name | `Competitor research for EU freight brokerage` |
152
+ | Description | `Research the top 5 competitors in EU freight brokerage and summarise their pricing models in a one-page brief.` |
153
+ | Conversation ID | *(optional)* `{{ $execution.id }}` — lets Tendem correlate several tasks from one run |
154
+
155
+ Output carries `task_id` and `last_seen_offset`. Nothing is charged yet.
156
+
157
+ **2. Task → Wait for Change.** Task ID `{{ $json.task_id }}`. This blocks until
158
+ Tendem needs you. When `next_action` comes back `await_input`, Tendem asked a
159
+ scoping question: read it with **Chat → Read** and answer with **Chat → Send**,
160
+ then wait again. Send figures out the conversation position on its own (that's
161
+ the "Resolve Offset Automatically" toggle, on by default), so there is no offset
162
+ to thread through the workflow. When `next_action` is `await_user_approval`, the
163
+ quote is ready.
164
+
165
+ **3. Task → Get Contract.** Returns the scope Tendem committed to
166
+ (`task_description`, `criteria`) and the price. Scope is ready before the price
167
+ is, so a contract can legitimately come back with `price: null` — that means keep
168
+ waiting, not approve at zero.
169
+
170
+ **4–6. Show a human the scope and the price, and wait for an answer.** This is
171
+ the part the node cannot do for you and deliberately will not fake. Any n8n
172
+ approval mechanism works: a Wait node with a form, a Slack interactive message, a
173
+ webhook.
174
+
175
+ **7. Task → Approve.**
176
+
177
+ | Parameter | Value |
178
+ |---|---|
179
+ | Task ID | `{{ $json.task_id }}` |
180
+ | Name | `{{ $json.name }}` |
181
+ | Price | `{{ $json.price }}` — the number the human was shown |
182
+ | Confirm Spend | `{{ $json.humanApproved === true }}` |
183
+
184
+ Route `spendBlocked === true` to a branch that sends the human `topupUrl`.
185
+
186
+ **8. Task → Wait for Change** again, until `next_action` is `fetch_result` or
187
+ `done`. Expert work takes minutes to hours, so set **Max Rounds** to what you're
188
+ willing to hold an execution open for (each round is at most 30 seconds) and
189
+ handle `tendemWait.timedOut === true` by re-entering the wait on a schedule
190
+ rather than by raising the cap.
191
+
192
+ **9. Task → Get Result.** Returns the result markdown plus pre-signed download
193
+ URLs for any files. Fetch those with an HTTP Request node if you need the bytes.
194
+
195
+ ## Polling without a busy loop
196
+
197
+ **Wait for Change** does not spin. Each round is a single
198
+ `get_task(task_id, wait_for_change_seconds=N)` call, and the *server* holds the
199
+ request open until the task actually changes — no client-side interval, no
200
+ repeated requests while nothing is happening.
201
+
202
+ | Parameter | Default | Range |
203
+ |---|---|---|
204
+ | Wait for Change (Seconds) | 30 | 5–30 (30 is the Tendem API's ceiling) |
205
+ | Max Rounds | 20 | 1–240 |
206
+
207
+ The round count is a hard cap. When the budget runs out the node emits the latest
208
+ snapshot with:
209
+
210
+ ```json
211
+ { "tendemWait": { "settled": false, "timedOut": true, "rounds": 20 } }
212
+ ```
213
+
214
+ Branch on `tendemWait.timedOut` and re-enter the wait later. At the defaults, one
215
+ node holds an execution open for at most ten minutes.
216
+
217
+ There's a backstop underneath: if a round returns faster than the server could
218
+ plausibly have blocked — a proxy that doesn't support long-polling, say — the node
219
+ sleeps before the next one, honouring Tendem's `poll_after_seconds` hint. A
220
+ misbehaving endpoint degrades to a paced poll, never to a hot loop.
221
+
222
+ Transient failures are absorbed too: read operations retry a
223
+ `TEMPORARILY_UNAVAILABLE`, a 5xx, or a dropped connection with backoff (up to 5
224
+ attempts) instead of failing the workflow, so an hours-long expert wait survives
225
+ the blips it will inevitably see. Operations that write — Create, Send, Approve —
226
+ are never retried, because repeating them could duplicate a task, a message, or
227
+ a charge.
228
+
229
+ ## Attaching input files
230
+
231
+ Uploads need a `task_id`, so they can only happen *after* Create.
232
+
233
+ 1. **File → Get Upload URL** with the task ID. You get a short-lived, folder-level
234
+ pre-signed URL.
235
+ 2. For each file, build the PUT URL from the folder URL and upload with an HTTP
236
+ Request node:
237
+ - swap the host from `.dfs.core.windows.net` to `.blob.core.windows.net`,
238
+ - append the file name to the path **before** the query string —
239
+ `<base>/<filename>?<query>`,
240
+ - `PUT` the raw bytes with the header `x-ms-blob-type: BlockBlob`.
241
+
242
+ All three matter: a `PUT` to the URL exactly as returned fails with HTTP 400.
243
+ Keep names simple; avoid spaces. Subpaths like `data/input.csv` are fine.
244
+ 3. **Chat → Send** naming the files you uploaded, e.g.
245
+ `I've uploaded brief.pdf and data/input.csv for this task.` Tendem waits for
246
+ this message; without it the expert never sees the files.
247
+
248
+ If the brief already references the files, mention them in the Create description
249
+ and promise them. Tendem may ask for them before your upload finishes — that race
250
+ is expected, and the confirming chat message settles it.
251
+
252
+ ## Compatibility
253
+
254
+ - n8n API version 1, node type version 1
255
+ - Node.js >= 20.19
256
+ - No runtime dependencies. The MCP client is implemented in this package, in
257
+ ~350 lines, against the [Streamable HTTP
258
+ transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports)
259
+ spec — so there is nothing to audit but this repository.
260
+
261
+ ## Support
262
+
263
+ - Issues: <https://github.com/Toloka/tendem-mcp/issues>
264
+ - Email: <support@tendem.ai>
265
+
266
+ ## License
267
+
268
+ [MIT](./LICENSE) © Toloka AI BV
@@ -0,0 +1,10 @@
1
+ import type { IAuthenticateGeneric, Icon, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class TendemApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ icon: Icon;
6
+ documentationUrl: string;
7
+ properties: INodeProperties[];
8
+ authenticate: IAuthenticateGeneric;
9
+ test: ICredentialTestRequest;
10
+ }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TendemApi = void 0;
4
+ const transport_1 = require("../nodes/Tendem/transport");
5
+ class TendemApi {
6
+ constructor() {
7
+ this.name = 'tendemApi';
8
+ this.displayName = 'Tendem API';
9
+ this.icon = 'file:../nodes/Tendem/tendem.svg';
10
+ this.documentationUrl = 'https://github.com/Toloka/tendem-mcp';
11
+ this.properties = [
12
+ {
13
+ displayName: 'API Key',
14
+ name: 'apiKey',
15
+ type: 'string',
16
+ typeOptions: { password: true },
17
+ default: '',
18
+ required: true,
19
+ description: 'Tendem API key. Create one at https://agent.tendem.ai/mcp, on the "Agent builders" tab. Sent as the "Authorization: ApiKey <token>" header.',
20
+ },
21
+ {
22
+ displayName: 'MCP Endpoint',
23
+ name: 'endpoint',
24
+ type: 'string',
25
+ default: transport_1.TENDEM_DEFAULT_ENDPOINT,
26
+ required: true,
27
+ description: 'Tendem MCP endpoint (Streamable HTTP). Change this only to target a non-production Tendem deployment.',
28
+ },
29
+ ];
30
+ this.authenticate = {
31
+ type: 'generic',
32
+ properties: {
33
+ headers: {
34
+ Authorization: '=ApiKey {{$credentials.apiKey}}',
35
+ },
36
+ },
37
+ };
38
+ this.test = {
39
+ request: {
40
+ url: '={{$credentials.endpoint}}',
41
+ method: 'POST',
42
+ headers: {
43
+ Accept: 'application/json, text/event-stream',
44
+ 'Content-Type': 'application/json',
45
+ },
46
+ body: {
47
+ jsonrpc: '2.0',
48
+ id: 1,
49
+ method: 'initialize',
50
+ params: {
51
+ protocolVersion: transport_1.MCP_PROTOCOL_VERSION,
52
+ capabilities: {},
53
+ clientInfo: { name: transport_1.MCP_CLIENT_NAME, version: transport_1.MCP_CLIENT_VERSION },
54
+ },
55
+ },
56
+ },
57
+ };
58
+ }
59
+ }
60
+ exports.TendemApi = TendemApi;
61
+ //# sourceMappingURL=TendemApi.credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TendemApi.credentials.js","sourceRoot":"","sources":["../../credentials/TendemApi.credentials.ts"],"names":[],"mappings":";;;AAQA,yDAKmC;AAEnC,MAAa,SAAS;IAAtB;QACC,SAAI,GAAG,WAAW,CAAC;QAEnB,gBAAW,GAAG,YAAY,CAAC;QAO3B,SAAI,GAAS,iCAAiC,CAAC;QAE/C,qBAAgB,GAAG,sCAAsC,CAAC;QAE1D,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,SAAS;gBACtB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EACV,6IAA6I;aAC9I;YACD;gBACC,WAAW,EAAE,cAAc;gBAC3B,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,mCAAuB;gBAChC,QAAQ,EAAE,IAAI;gBACd,WAAW,EACV,uGAAuG;aACxG;SACD,CAAC;QAEF,iBAAY,GAAyB;YACpC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE;gBACX,OAAO,EAAE;oBACR,aAAa,EAAE,iCAAiC;iBAChD;aACD;SACD,CAAC;QAGF,SAAI,GAA2B;YAC9B,OAAO,EAAE;gBACR,GAAG,EAAE,4BAA4B;gBACjC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACR,MAAM,EAAE,qCAAqC;oBAC7C,cAAc,EAAE,kBAAkB;iBAClC;gBACD,IAAI,EAAE;oBACL,OAAO,EAAE,KAAK;oBACd,EAAE,EAAE,CAAC;oBACL,MAAM,EAAE,YAAY;oBACpB,MAAM,EAAE;wBACP,eAAe,EAAE,gCAAoB;wBACrC,YAAY,EAAE,EAAE;wBAChB,UAAU,EAAE,EAAE,IAAI,EAAE,2BAAe,EAAE,OAAO,EAAE,8BAAkB,EAAE;qBAClE;iBACD;aACD;SACD,CAAC;IACH,CAAC;CAAA;AAlED,8BAkEC"}
@@ -0,0 +1,5 @@
1
+ import { type IExecuteFunctions, type INodeExecutionData, type INodeType, type INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class Tendem implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,211 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Tendem = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const descriptions_1 = require("./descriptions");
6
+ const transport_1 = require("./transport");
7
+ const retry_1 = require("./retry");
8
+ const tools_1 = require("./tools");
9
+ const waitForTask_1 = require("./waitForTask");
10
+ class Tendem {
11
+ constructor() {
12
+ this.description = {
13
+ displayName: 'Tendem',
14
+ name: 'tendem',
15
+ icon: 'file:tendem.svg',
16
+ group: ['transform'],
17
+ version: 1,
18
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
19
+ description: 'Delegate work to vetted human experts through Tendem',
20
+ defaults: { name: 'Tendem' },
21
+ inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
22
+ outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
23
+ credentials: [{ name: 'tendemApi', required: true }],
24
+ properties: [
25
+ descriptions_1.resourceField,
26
+ descriptions_1.taskOperations,
27
+ descriptions_1.chatOperations,
28
+ descriptions_1.accountOperations,
29
+ descriptions_1.fileOperations,
30
+ ...descriptions_1.taskFields,
31
+ ...descriptions_1.chatFields,
32
+ ...descriptions_1.fileFields,
33
+ ],
34
+ };
35
+ }
36
+ async execute() {
37
+ const items = this.getInputData();
38
+ const returnData = [];
39
+ const credentials = await this.getCredentials('tendemApi');
40
+ const endpoint = typeof credentials.endpoint === 'string' && credentials.endpoint.trim() !== ''
41
+ ? credentials.endpoint.trim()
42
+ : transport_1.TENDEM_DEFAULT_ENDPOINT;
43
+ const requester = async (options) => (await this.helpers.httpRequestWithAuthentication.call(this, 'tendemApi', options));
44
+ const session = new transport_1.McpSession(requester, { endpoint });
45
+ const retrying = new retry_1.RetryingToolCaller(session, { sleep: n8n_workflow_1.sleep });
46
+ for (let i = 0; i < items.length; i += 1) {
47
+ try {
48
+ const resource = this.getNodeParameter('resource', i);
49
+ const operation = this.getNodeParameter('operation', i);
50
+ const key = (0, tools_1.operationKey)(resource, operation);
51
+ const guarded = (0, tools_1.guardFor)(retrying, key);
52
+ const payload = await runOperation.call(this, guarded, key, i);
53
+ returnData.push(...this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray(payload), {
54
+ itemData: { item: i },
55
+ }));
56
+ }
57
+ catch (error) {
58
+ if (this.continueOnFail()) {
59
+ returnData.push({
60
+ json: { error: error instanceof Error ? error.message : String(error) },
61
+ pairedItem: { item: i },
62
+ });
63
+ continue;
64
+ }
65
+ throw asNodeError.call(this, error, i);
66
+ }
67
+ }
68
+ return [returnData];
69
+ }
70
+ }
71
+ exports.Tendem = Tendem;
72
+ function asNodeError(error, itemIndex) {
73
+ if (error instanceof n8n_workflow_1.NodeOperationError || error instanceof n8n_workflow_1.NodeApiError)
74
+ return error;
75
+ return new n8n_workflow_1.NodeApiError(this.getNode(), error, {
76
+ itemIndex,
77
+ message: error instanceof Error ? error.message : String(error),
78
+ });
79
+ }
80
+ async function runOperation(guarded, key, i) {
81
+ switch (key) {
82
+ case 'task:create': {
83
+ const args = {
84
+ name: this.getNodeParameter('taskName', i),
85
+ description: this.getNodeParameter('description', i),
86
+ };
87
+ const conversationId = this.getNodeParameter('conversationId', i, '');
88
+ if (conversationId !== '')
89
+ args.conversation_id = conversationId;
90
+ return await guarded.callTool(tools_1.TENDEM_TOOLS.CREATE_TASK, args);
91
+ }
92
+ case 'task:get':
93
+ return await guarded.callTool(tools_1.TENDEM_TOOLS.GET_TASK, {
94
+ task_id: this.getNodeParameter('taskId', i),
95
+ });
96
+ case 'task:getContract':
97
+ return await guarded.callTool(tools_1.TENDEM_TOOLS.GET_CONTRACT, {
98
+ task_id: this.getNodeParameter('taskId', i),
99
+ });
100
+ case 'task:approve':
101
+ return await approveTask.call(this, guarded, i);
102
+ case 'task:cancel':
103
+ return await guarded.callTool(tools_1.TENDEM_TOOLS.CANCEL_TASK, {
104
+ task_id: this.getNodeParameter('taskId', i),
105
+ name: this.getNodeParameter('taskName', i),
106
+ });
107
+ case 'task:getResult':
108
+ return await guarded.callTool(tools_1.TENDEM_TOOLS.GET_TASK_RESULT, {
109
+ task_id: this.getNodeParameter('taskId', i),
110
+ });
111
+ case 'task:list':
112
+ return await guarded.callTool(tools_1.TENDEM_TOOLS.LIST_TASKS, {
113
+ limit: this.getNodeParameter('limit', i, 50),
114
+ offset: this.getNodeParameter('offset', i, 0),
115
+ });
116
+ case 'task:wait': {
117
+ const outcome = await (0, waitForTask_1.waitForTaskChange)({ caller: guarded, sleep: n8n_workflow_1.sleep, now: () => Date.now() }, {
118
+ taskId: this.getNodeParameter('taskId', i),
119
+ waitForChangeSeconds: this.getNodeParameter('waitForChangeSeconds', i, 30),
120
+ maxRounds: this.getNodeParameter('maxRounds', i, 20),
121
+ });
122
+ return {
123
+ ...outcome.task,
124
+ tendemWait: {
125
+ settled: outcome.settled,
126
+ timedOut: outcome.timedOut,
127
+ rounds: outcome.rounds,
128
+ },
129
+ };
130
+ }
131
+ case 'chat:read':
132
+ return await guarded.callTool(tools_1.TENDEM_TOOLS.READ_CHAT, {
133
+ task_id: this.getNodeParameter('taskId', i),
134
+ from_offset: this.getNodeParameter('fromOffset', i, 0),
135
+ });
136
+ case 'chat:send':
137
+ return await sendChatMessage.call(this, guarded, i);
138
+ case 'account:get':
139
+ return await guarded.callTool(tools_1.TENDEM_TOOLS.GET_ACCOUNT, {});
140
+ case 'file:getUploadUrl':
141
+ return await guarded.callTool(tools_1.TENDEM_TOOLS.GET_FILE_UPLOAD_URL, {
142
+ task_id: this.getNodeParameter('taskId', i),
143
+ });
144
+ default:
145
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unsupported Tendem operation "${key}"`, {
146
+ itemIndex: i,
147
+ });
148
+ }
149
+ }
150
+ async function sendChatMessage(guarded, i) {
151
+ const taskId = this.getNodeParameter('taskId', i);
152
+ const text = this.getNodeParameter('text', i);
153
+ const autoOffset = this.getNodeParameter('autoOffset', i, true);
154
+ const latestOffset = async () => {
155
+ const chat = await guarded.callTool(tools_1.TENDEM_TOOLS.READ_CHAT, {
156
+ task_id: taskId,
157
+ from_offset: 0,
158
+ });
159
+ return typeof chat.last_seen_offset === 'number' ? chat.last_seen_offset : 0;
160
+ };
161
+ let offset = autoOffset
162
+ ? await latestOffset()
163
+ : this.getNodeParameter('lastSeenOffset', i, 0);
164
+ let response = await guarded.callTool(tools_1.TENDEM_TOOLS.SEND_MESSAGE, {
165
+ task_id: taskId,
166
+ text,
167
+ last_seen_offset: offset,
168
+ });
169
+ if (autoOffset && response.response_type === 'race') {
170
+ offset =
171
+ typeof response.last_seen_offset === 'number' ? response.last_seen_offset : await latestOffset();
172
+ response = await guarded.callTool(tools_1.TENDEM_TOOLS.SEND_MESSAGE, {
173
+ task_id: taskId,
174
+ text,
175
+ last_seen_offset: offset,
176
+ });
177
+ }
178
+ return response;
179
+ }
180
+ async function approveTask(guarded, i) {
181
+ const taskId = this.getNodeParameter('taskId', i);
182
+ const taskName = this.getNodeParameter('taskName', i);
183
+ const price = this.getNodeParameter('price', i);
184
+ const confirmed = this.getNodeParameter('confirmSpend', i, false);
185
+ if (confirmed !== true) {
186
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Refusing to approve a Tendem task: the spend was not confirmed', {
187
+ itemIndex: i,
188
+ description: 'Approving charges the Tendem account. Read the scope and price with the "Get Contract" operation, surface it to a human, then enable "Confirm Spend" on this node.',
189
+ });
190
+ }
191
+ if (typeof price !== 'string' || price.trim() === '') {
192
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Refusing to approve a Tendem task: no price was supplied', {
193
+ itemIndex: i,
194
+ description: 'Pass the quoted price through from the Get Task or Get Contract operation, so the approval names the amount being committed.',
195
+ });
196
+ }
197
+ const response = await guarded.callTool(tools_1.TENDEM_TOOLS.APPROVE_TASK, {
198
+ task_id: taskId,
199
+ name: taskName,
200
+ price,
201
+ });
202
+ const approvedRaw = response.approved;
203
+ const approved = typeof approvedRaw === 'boolean' ? approvedRaw : undefined;
204
+ return {
205
+ ...response,
206
+ approved: approved === undefined ? null : approved,
207
+ spendBlocked: approved === false,
208
+ topupUrl: typeof response.topup_url === 'string' ? response.topup_url : null,
209
+ };
210
+ }
211
+ //# sourceMappingURL=Tendem.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tendem.node.js","sourceRoot":"","sources":["../../../nodes/Tendem/Tendem.node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ {
2
+ "node": "n8n-nodes-tendem.tendem",
3
+ "nodeVersion": "1.0",
4
+ "codexVersion": "1.0",
5
+ "categories": ["Utility", "Productivity"],
6
+ "resources": {
7
+ "credentialDocumentation": [
8
+ {
9
+ "url": "https://github.com/Toloka/tendem-mcp/tree/main/integrations/n8n-nodes-tendem#credentials"
10
+ }
11
+ ],
12
+ "primaryDocumentation": [
13
+ {
14
+ "url": "https://github.com/Toloka/tendem-mcp/tree/main/integrations/n8n-nodes-tendem"
15
+ }
16
+ ]
17
+ }
18
+ }
@@ -0,0 +1,9 @@
1
+ import type { INodeProperties } from 'n8n-workflow';
2
+ export declare const resourceField: INodeProperties;
3
+ export declare const taskOperations: INodeProperties;
4
+ export declare const chatOperations: INodeProperties;
5
+ export declare const accountOperations: INodeProperties;
6
+ export declare const fileOperations: INodeProperties;
7
+ export declare const taskFields: INodeProperties[];
8
+ export declare const chatFields: INodeProperties[];
9
+ export declare const fileFields: INodeProperties[];