@taifoon/n8n-nodes-typesafe 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 +18 -0
- package/README.md +183 -0
- package/dist/credentials/TaifoonGatewayApi.credentials.d.ts +13 -0
- package/dist/credentials/TaifoonGatewayApi.credentials.js +31 -0
- package/dist/credentials/TaifoonGatewayApi.credentials.js.map +1 -0
- package/dist/credentials/TypeSafeApi.credentials.d.ts +10 -0
- package/dist/credentials/TypeSafeApi.credentials.js +22 -0
- package/dist/credentials/TypeSafeApi.credentials.js.map +1 -0
- package/dist/credentials/taifoon.svg +1 -0
- package/dist/nodes/TaifoonTypeSafe/TaifoonTypeSafe.node.d.ts +5 -0
- package/dist/nodes/TaifoonTypeSafe/TaifoonTypeSafe.node.js +215 -0
- package/dist/nodes/TaifoonTypeSafe/TaifoonTypeSafe.node.js.map +1 -0
- package/dist/nodes/TaifoonTypeSafe/TaifoonTypeSafe.node.json +1 -0
- package/dist/nodes/TaifoonTypeSafe/taifoonTypeSafe.svg +1 -0
- package/dist/nodes/TaifoonTypeSafe/translate.d.ts +49 -0
- package/dist/nodes/TaifoonTypeSafe/translate.js +216 -0
- package/dist/nodes/TaifoonTypeSafe/translate.js.map +1 -0
- package/dist/package.json +69 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/docs/KEY_POLICY.md +58 -0
- package/docs/SECURE_KEYS.md +81 -0
- package/docs/TRANSLATION.md +53 -0
- package/docs/WORKFLOWS.md +30 -0
- package/index.js +1 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Taifoon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
6
|
+
associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
7
|
+
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
8
|
+
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
9
|
+
subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
12
|
+
portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
15
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
16
|
+
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
17
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
18
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# TypeSafe for n8n
|
|
2
|
+
|
|
3
|
+
Most automations have a moment where someone has to *decide*: is this a refund request, which team
|
|
4
|
+
gets this ticket, how urgent is it, is this invoice a duplicate. Today you either write brittle rules
|
|
5
|
+
for that, or you ask a chat model and then fight with its prose: parse the answer, handle the day it
|
|
6
|
+
says "It depends", pay for a paragraph you throw away.
|
|
7
|
+
|
|
8
|
+
This node does the deciding and nothing else. You hand it an item and a few questions. It hands back
|
|
9
|
+
answers your workflow can branch on directly, with a probability attached, usually in well under a
|
|
10
|
+
second and for about two thousandths of a cent.
|
|
11
|
+
|
|
12
|
+
It works by calling [TypeSafe's Jev](https://docs.typesafe.ai/introduction), a model built to make
|
|
13
|
+
decisions rather than write text. You need a TypeSafe API key, which you get from
|
|
14
|
+
[console.typesafe.ai](https://console.typesafe.ai). That is the only account involved: the node talks
|
|
15
|
+
to TypeSafe directly, and nobody else, including us, is in the path.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
item ──► TypeSafe ──► Pass confident, and it cleared your thresholds
|
|
19
|
+
├──► Fail confident, and it did not
|
|
20
|
+
└──► Review unsure, or the answer did not validate: send this to a person
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## The idea: three systems, each doing the one thing it is good at
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
n8n Taifoon TypeSafe
|
|
27
|
+
the workflow the coordination layer the judge
|
|
28
|
+
───────────── ────────────────────── ─────────
|
|
29
|
+
gathers the item ──► turns your words into ──► answers each question
|
|
30
|
+
runs the branches typed questions with a probability
|
|
31
|
+
▲ turns the answers back ◄──
|
|
32
|
+
└──────────────── into Pass / Fail / Review
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- **n8n** is where your process already lives: the triggers, the data, the people who get notified.
|
|
36
|
+
It is good at moving things and bad at judgment.
|
|
37
|
+
- **TypeSafe** is a model that only judges. It cannot write an essay, which is the point: it returns
|
|
38
|
+
a number you can threshold, quickly and cheaply, instead of prose you have to interpret.
|
|
39
|
+
- **Taifoon's part is the layer between them**, and it is plain code that ships inside this node. Going
|
|
40
|
+
in, it compiles what you mean ("is this a refund?") into the three question types the model
|
|
41
|
+
understands. Coming out, it compiles the model's probabilities into the only three things a workflow
|
|
42
|
+
can act on: go ahead, do not, or ask a human. Every threshold in that step is yours and sits on the
|
|
43
|
+
canvas where you can see it.
|
|
44
|
+
|
|
45
|
+
Why three outputs and not two: a yes/no forces a confident answer even when the model is guessing, and
|
|
46
|
+
that is how automations go wrong silently. **Review** is the honest third option. It is where the
|
|
47
|
+
low-confidence cases and the malformed answers go, so a person sees exactly the items that need one.
|
|
48
|
+
|
|
49
|
+
## Who this is for
|
|
50
|
+
|
|
51
|
+
- **Support and ops teams** routing tickets, emails and alerts without maintaining a wall of IF nodes.
|
|
52
|
+
- **Anyone putting an LLM in a workflow** who wants a cheap, fast guard in front of it or behind it:
|
|
53
|
+
is this input safe, is this output on topic, does it contain personal data.
|
|
54
|
+
- **Builders of data pipelines** who need to classify, de-duplicate or score thousands of rows and
|
|
55
|
+
cannot afford, or wait for, a chat model on each one.
|
|
56
|
+
- **People who do not trust a yes/no without a number.** Every answer comes with how sure the model
|
|
57
|
+
is, so the uncertain cases go to a human instead of going wrong quietly.
|
|
58
|
+
|
|
59
|
+
It is not for writing text, summarising, or reasoning about code. We measured that honestly; see
|
|
60
|
+
[What it is good and bad at](#what-it-is-good-and-bad-at).
|
|
61
|
+
|
|
62
|
+
## Three kinds of question
|
|
63
|
+
|
|
64
|
+
| You ask | You get back | Think of it as |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| **Yes / no** ("Noul") | `p`, the probability the statement is true | an IF with a dial |
|
|
67
|
+
| **Pick one** ("Choice") | the option, a probability for every option, and a `confidence` | a Switch that knows when it is guessing |
|
|
68
|
+
| **Rate it** ("Score") | a level on a rubric you write, and a `confidence` | a ranking you can threshold |
|
|
69
|
+
|
|
70
|
+
Ask all the questions that might matter in the same node. They are answered at once and independently,
|
|
71
|
+
so ten questions cost about the same as one.
|
|
72
|
+
|
|
73
|
+
## Install
|
|
74
|
+
|
|
75
|
+
In self-hosted n8n: **Settings → Community Nodes → Install**, then enter `@taifoon/n8n-nodes-typesafe`.
|
|
76
|
+
|
|
77
|
+
**No key yet?** Pick the **Free Trial** connection: three real answers with no account and no key, on us
|
|
78
|
+
(up to 4 questions and 4,000 characters per call). It exists so you can see a real result before signing
|
|
79
|
+
up anywhere.
|
|
80
|
+
|
|
81
|
+
When you are ready, create a **TypeSafe API** credential and paste your key. The test button makes one tiny real call, so
|
|
82
|
+
you find out immediately whether the key works. Running n8n for a team? You can provision the key from a
|
|
83
|
+
secrets file so nobody ever sees it: [Supplying keys securely](docs/SECURE_KEYS.md).
|
|
84
|
+
|
|
85
|
+
## Try it in two minutes
|
|
86
|
+
|
|
87
|
+
1. Add a **Manual Trigger** and an **Edit Fields** node with a `subject` and a `body`: paste in any
|
|
88
|
+
support email.
|
|
89
|
+
2. Add **TypeSafe**, operation **Ask**. Leave *Item to Judge* alone; it already sends the whole item.
|
|
90
|
+
Add three questions:
|
|
91
|
+
- `is_refund` · Yes/no · *Is the customer asking for money back?*
|
|
92
|
+
- `team` · Pick one · *Which team should handle this?* · `billing, technical, sales, abuse`
|
|
93
|
+
- `urgency` · Rate it · *How urgent is this?* · `None | Low | Medium | High`
|
|
94
|
+
3. Run it. You get `answers.is_refund.p`, `answers.team.value`, `answers.urgency.value`.
|
|
95
|
+
4. Now make it branch. In **Routing** put `{"team": {"minConfidence": 0.6}}`. Tickets the model is sure
|
|
96
|
+
about leave by **Pass**; the ones it is unsure about leave by **Review**. Wire Review to a person.
|
|
97
|
+
|
|
98
|
+
Ready-made versions are in [`examples/`](examples).
|
|
99
|
+
|
|
100
|
+
## Do not want to write the questions? Describe the job
|
|
101
|
+
|
|
102
|
+
The **Translate** operation turns a sentence into questions:
|
|
103
|
+
|
|
104
|
+
> *Check if the customer is asking for a refund. Classify the ticket into billing, technical, sales or
|
|
105
|
+
> abuse. Rate the urgency from 1 to 5.*
|
|
106
|
+
|
|
107
|
+
becomes a yes/no, a pick-one with exactly those four options, and a five-level rating. It runs inside
|
|
108
|
+
the node: no network call, no key, no cost, and the same sentence always gives the same result.
|
|
109
|
+
|
|
110
|
+
It understands **English, Spanish, German, French, Portuguese, Italian, Polish, Dutch, Russian, Japanese
|
|
111
|
+
and Arabic**, detects the language per sentence, and you can mix them in one task. Anything else still
|
|
112
|
+
works as a yes/no.
|
|
113
|
+
|
|
114
|
+
**Your language is not here? Please add it.** A language is one small word pack in
|
|
115
|
+
[`nodes/TaifoonTypeSafe/translate.ts`](nodes/TaifoonTypeSafe/translate.ts): the verbs that mean "pick
|
|
116
|
+
one", the words that mean "rate it", how options are introduced and separated, how a scale is written,
|
|
117
|
+
and a four-level default rubric. No logic changes. Add the pack, add one test sentence to the self-test,
|
|
118
|
+
open a pull request. Native speakers catch what we cannot: we would especially welcome Chinese, Korean,
|
|
119
|
+
Hindi, Turkish, Ukrainian, Swedish, Hebrew and Indonesian, and corrections to the eleven we ship.
|
|
120
|
+
|
|
121
|
+
It is deliberately literal. It will not invent categories you did not name: *"classify this ticket"*
|
|
122
|
+
with no list comes back flagged `needs_input`. It suggests thresholds but never applies them for you,
|
|
123
|
+
for the reason in the next section.
|
|
124
|
+
|
|
125
|
+
## The one rule about routing
|
|
126
|
+
|
|
127
|
+
An item leaves by **Pass** only if *every* question you put in Routing passed. So only route the
|
|
128
|
+
questions you actually want to gate on. If you route `urgency` as well, a perfectly good refund ticket
|
|
129
|
+
"fails" just because it is not urgent. We made exactly that mistake while building this.
|
|
130
|
+
|
|
131
|
+
| Question | Routing keys | What happens |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| Yes / no | `gte`, `lte` on `p` | pass or fail |
|
|
134
|
+
| Pick one | `minConfidence`, and `in` for the options you accept | below the confidence → **Review** |
|
|
135
|
+
| Rate it | `min`, `max` on the level | pass or fail |
|
|
136
|
+
|
|
137
|
+
Two details: a rating is a **zero-based level number** (0 is your first level; every answer includes a
|
|
138
|
+
`legend`), and an answer that does not validate always goes to Review. Nothing fails open.
|
|
139
|
+
|
|
140
|
+
## What it is good and bad at
|
|
141
|
+
|
|
142
|
+
We benchmarked it against Claude Sonnet, and the results are mixed in a useful way:
|
|
143
|
+
|
|
144
|
+
- **Answering a real system's yes/no checks:** it matched or beat Sonnet on every decision.
|
|
145
|
+
- **Forecasting next-day rain from two days of weather:** a tie (81% against 78%), and neither clearly
|
|
146
|
+
beat the naive "same as today".
|
|
147
|
+
- **Judging claims about small Python functions:** Sonnet got 100%, this got 83%. It is not a code
|
|
148
|
+
reasoner.
|
|
149
|
+
|
|
150
|
+
In all three it was about **ten times faster and a thousand times cheaper**. Its raw probabilities were
|
|
151
|
+
the less well calibrated of the two, which is the practical reason to **fit your thresholds on a few
|
|
152
|
+
dozen of your own labelled items** before trusting them.
|
|
153
|
+
|
|
154
|
+
## Habits that keep it reliable
|
|
155
|
+
|
|
156
|
+
- **Calculate first, then ask.** Do arithmetic in a Code node. Ask the model for judgment, never a sum.
|
|
157
|
+
- **One thing per question.** If a question weighs several factors, split it and combine the answers
|
|
158
|
+
yourself, with weights you can see.
|
|
159
|
+
- **Keep thresholds on the canvas,** where they can be reviewed and changed, not inside a prompt.
|
|
160
|
+
- **Leave Fail Closed on.** A malformed answer stops the item instead of flowing on as an empty value.
|
|
161
|
+
- **Remember what n8n stores.** By default n8n keeps every execution's data. If your items contain
|
|
162
|
+
personal data, set `EXECUTIONS_DATA_SAVE_ON_SUCCESS=none` on your instance. This node never writes
|
|
163
|
+
your key into an execution record, including when a request fails.
|
|
164
|
+
|
|
165
|
+
## Cost and limits
|
|
166
|
+
|
|
167
|
+
About 0.6 to 0.8 s and 450 input tokens for three questions. TypeSafe charges 0.042 USD per million
|
|
168
|
+
input tokens and nothing for output: roughly 0.00002 USD per item. Rate limits and overload responses
|
|
169
|
+
are retried with backoff. Input is text or JSON; no images or audio.
|
|
170
|
+
|
|
171
|
+
## More
|
|
172
|
+
|
|
173
|
+
[Supplying keys securely](docs/SECURE_KEYS.md) · [Workflow patterns](docs/WORKFLOWS.md) ·
|
|
174
|
+
[How Translate works, rule by rule](docs/TRANSLATION.md) · [Key policy and rotation](docs/KEY_POLICY.md)
|
|
175
|
+
|
|
176
|
+
The node also has an optional second connection to the Taifoon gateway, for teams who want metering and
|
|
177
|
+
open-weights models alongside Jev. You do not need it, and it is documented in
|
|
178
|
+
[Key policy](docs/KEY_POLICY.md) rather than here.
|
|
179
|
+
|
|
180
|
+
## Licence
|
|
181
|
+
|
|
182
|
+
MIT. An independent community node by [Taifoon](https://github.com/taifoon-io). TypeSafe and Jev are
|
|
183
|
+
trademarks of TypeSafe AI; this project is not affiliated with or endorsed by TypeSafe AI.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IAuthenticateGeneric, ICredentialDataDecryptedObject, ICredentialTestRequest, ICredentialType, IHttpRequestHelper, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class TaifoonGatewayApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
icon: "file:taifoon.svg";
|
|
6
|
+
documentationUrl: string;
|
|
7
|
+
properties: INodeProperties[];
|
|
8
|
+
preAuthentication(this: IHttpRequestHelper, credentials: ICredentialDataDecryptedObject): Promise<{
|
|
9
|
+
sessionToken: string;
|
|
10
|
+
}>;
|
|
11
|
+
authenticate: IAuthenticateGeneric;
|
|
12
|
+
test: ICredentialTestRequest;
|
|
13
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TaifoonGatewayApi = void 0;
|
|
4
|
+
class TaifoonGatewayApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'taifoonGatewayApi';
|
|
7
|
+
this.displayName = 'Taifoon Gateway API';
|
|
8
|
+
this.icon = 'file:taifoon.svg';
|
|
9
|
+
this.documentationUrl = 'https://deck.taifoon.dev';
|
|
10
|
+
this.properties = [
|
|
11
|
+
{ displayName: 'Session', name: 'sessionToken', type: 'hidden', typeOptions: { expirable: true, password: true }, default: '' },
|
|
12
|
+
{ displayName: 'Deck URL', name: 'deckUrl', type: 'string', default: 'https://deck.taifoon.dev', description: 'The Taifoon deck that fronts the typed-decision lanes' },
|
|
13
|
+
{ displayName: 'Taifoon Principal Key', name: 'principalKey', type: 'string', typeOptions: { password: true }, default: '', required: true, description: 'Your tfn_live_ key. It identifies you, carries your licence and is what usage is billed to.' },
|
|
14
|
+
{ displayName: 'TypeSafe API Key (Optional)', name: 'typesafeKey', type: 'string', typeOptions: { password: true }, default: '', description: 'Your own key from console.typesafe.ai. Leave empty to use the free trial pings. Needs the jev licence on your Taifoon key.' },
|
|
15
|
+
];
|
|
16
|
+
this.authenticate = {
|
|
17
|
+
type: 'generic',
|
|
18
|
+
properties: { headers: { Cookie: '={{$credentials.sessionToken}}', 'x-typesafe-key': '={{$credentials.typesafeKey || undefined}}' } },
|
|
19
|
+
};
|
|
20
|
+
this.test = { request: { baseURL: '={{$credentials.deckUrl}}', url: '/api/typed', method: 'GET' } };
|
|
21
|
+
}
|
|
22
|
+
async preAuthentication(credentials) {
|
|
23
|
+
const base = String(credentials.deckUrl || 'https://deck.taifoon.dev').replace(/\/$/, '');
|
|
24
|
+
const res = (await this.helpers.httpRequest({ method: 'POST', url: `${base}/api/login`, body: { key: credentials.principalKey }, json: true, returnFullResponse: true }));
|
|
25
|
+
const raw = res.headers['set-cookie'];
|
|
26
|
+
const cookie = (Array.isArray(raw) ? raw : [String(raw !== null && raw !== void 0 ? raw : '')]).map((c) => String(c).split(';')[0]).filter(Boolean).join('; ');
|
|
27
|
+
return { sessionToken: cookie };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.TaifoonGatewayApi = TaifoonGatewayApi;
|
|
31
|
+
//# sourceMappingURL=TaifoonGatewayApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaifoonGatewayApi.credentials.js","sourceRoot":"","sources":["../../credentials/TaifoonGatewayApi.credentials.ts"],"names":[],"mappings":";;;AAgBA,MAAa,iBAAiB;IAA9B;QACC,SAAI,GAAG,mBAAmB,CAAC;QAE3B,gBAAW,GAAG,qBAAqB,CAAC;QAEpC,SAAI,GAAG,kBAA2B,CAAC;QAEnC,qBAAgB,GAAG,0BAA0B,CAAC;QAE9C,eAAU,GAAsB;YAC/B,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;YAC/H,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,0BAA0B,EAAE,WAAW,EAAE,uDAAuD,EAAE;YACvK,EAAE,WAAW,EAAE,uBAAuB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,6FAA6F,EAAE;YACxP,EAAE,WAAW,EAAE,6BAA6B,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,WAAW,EAAE,4HAA4H,EAAE;SAC5Q,CAAC;QAUF,iBAAY,GAAyB;YACpC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,gCAAgC,EAAE,gBAAgB,EAAE,4CAA4C,EAAE,EAAE;SACrI,CAAC;QAEF,SAAI,GAA2B,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,2BAA2B,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;IACxH,CAAC;IAdA,KAAK,CAAC,iBAAiB,CAA2B,WAA2C;QAC5F,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,IAAI,0BAA0B,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1F,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,YAAY,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,WAAW,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAA+D,CAAC;QACxO,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,aAAH,GAAG,cAAH,GAAG,GAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/H,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;IACjC,CAAC;CAQD;AA9BD,8CA8BC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class TypeSafeApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
icon: "file:taifoon.svg";
|
|
6
|
+
documentationUrl: string;
|
|
7
|
+
properties: INodeProperties[];
|
|
8
|
+
authenticate: IAuthenticateGeneric;
|
|
9
|
+
test: ICredentialTestRequest;
|
|
10
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TypeSafeApi = void 0;
|
|
4
|
+
class TypeSafeApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'typeSafeApi';
|
|
7
|
+
this.displayName = 'TypeSafe API';
|
|
8
|
+
this.icon = 'file:taifoon.svg';
|
|
9
|
+
this.documentationUrl = 'https://docs.typesafe.ai/introduction/quickstart';
|
|
10
|
+
this.properties = [
|
|
11
|
+
{ displayName: 'API Key', name: 'apiKey', type: 'string', typeOptions: { password: true }, default: '', required: true, description: 'From console.typesafe.ai' },
|
|
12
|
+
{ displayName: 'Base URL', name: 'baseUrl', type: 'string', default: 'https://api.typesafe.ai', description: 'Change only for a proxy or a private deployment' },
|
|
13
|
+
];
|
|
14
|
+
this.authenticate = { type: 'generic', properties: { headers: { Authorization: '=Bearer {{$credentials.apiKey}}' } } };
|
|
15
|
+
this.test = {
|
|
16
|
+
request: { baseURL: '={{$credentials.baseUrl}}', url: '/v1/systemone', method: 'POST',
|
|
17
|
+
body: { model: 'jev-latest', state: 'the sky is blue', questions: { ok: { type: 'noul', instructions: 'Does the state mention a colour?' } } } },
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.TypeSafeApi = TypeSafeApi;
|
|
22
|
+
//# sourceMappingURL=TypeSafeApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypeSafeApi.credentials.js","sourceRoot":"","sources":["../../credentials/TypeSafeApi.credentials.ts"],"names":[],"mappings":";;;AAMA,MAAa,WAAW;IAAxB;QACC,SAAI,GAAG,aAAa,CAAC;QAErB,gBAAW,GAAG,cAAc,CAAC;QAE7B,SAAI,GAAG,kBAA2B,CAAC;QAEnC,qBAAgB,GAAG,kDAAkD,CAAC;QAEtE,eAAU,GAAsB;YAC/B,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,0BAA0B,EAAE;YACjK,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,yBAAyB,EAAE,WAAW,EAAE,iDAAiD,EAAE;SAChK,CAAC;QAEF,iBAAY,GAAyB,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,iCAAiC,EAAE,EAAE,EAAE,CAAC;QAGxI,SAAI,GAA2B;YAC9B,OAAO,EAAE,EAAE,OAAO,EAAE,2BAA2B,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM;gBACpF,IAAI,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,kCAAkC,EAAE,EAAE,EAAE,EAAE;SACjJ,CAAC;IACH,CAAC;CAAA;AArBD,kCAqBC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60"><rect width="60" height="60" rx="12" fill="#0d0f12"/><path d="M14 20h32M14 30h20M14 40h26" stroke="#7cc4ff" stroke-width="4" stroke-linecap="round"/><circle cx="46" cy="30" r="4" fill="#5fd39a"/></svg>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class TaifoonTypeSafe implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TaifoonTypeSafe = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const translate_1 = require("./translate");
|
|
6
|
+
const split = (s, sep) => String(s !== null && s !== void 0 ? s : '').split(sep).map((x) => x.trim()).filter(Boolean);
|
|
7
|
+
async function withBackoff(call) {
|
|
8
|
+
var _a, _b;
|
|
9
|
+
for (let attempt = 0;; attempt++) {
|
|
10
|
+
try {
|
|
11
|
+
return await call();
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
const status = Number((_a = error.httpCode) !== null && _a !== void 0 ? _a : (_b = error.response) === null || _b === void 0 ? void 0 : _b.status);
|
|
15
|
+
if ((status === 429 || status === 529) && attempt < 3) {
|
|
16
|
+
await (0, n8n_workflow_1.sleep)(500 * 2 ** attempt);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const TRIAL_URL = 'https://typesafe.taifoon.dev/v1/trial';
|
|
24
|
+
async function askTrial(ctx, body) {
|
|
25
|
+
return (await ctx.helpers.httpRequest({ method: 'POST', url: TRIAL_URL, body, json: true, timeout: 60000 }));
|
|
26
|
+
}
|
|
27
|
+
class TaifoonTypeSafe {
|
|
28
|
+
constructor() {
|
|
29
|
+
this.description = {
|
|
30
|
+
displayName: 'Taifoon TypeSafe',
|
|
31
|
+
name: 'taifoonTypeSafe',
|
|
32
|
+
icon: 'file:taifoonTypeSafe.svg',
|
|
33
|
+
group: ['transform'],
|
|
34
|
+
version: 1,
|
|
35
|
+
subtitle: '={{$parameter["operation"]}}',
|
|
36
|
+
description: 'Ask yes/no, pick-one and rate-it questions about any item and route on calibrated answers',
|
|
37
|
+
defaults: { name: 'TypeSafe' },
|
|
38
|
+
inputs: ['main'],
|
|
39
|
+
outputs: ['main', 'main', 'main'],
|
|
40
|
+
outputNames: ['Pass', 'Fail', 'Review'],
|
|
41
|
+
usableAsTool: true,
|
|
42
|
+
credentials: [
|
|
43
|
+
{ name: 'typeSafeApi', required: true, displayOptions: { show: { operation: ['ask'], connection: ['direct'] } } },
|
|
44
|
+
{ name: 'taifoonGatewayApi', required: true, displayOptions: { show: { operation: ['ask', 'lanes'], connection: ['taifoon'] } } },
|
|
45
|
+
],
|
|
46
|
+
properties: [
|
|
47
|
+
{ displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, default: 'ask',
|
|
48
|
+
options: [
|
|
49
|
+
{ name: 'Ask', value: 'ask', action: 'Ask typed questions about an item', description: 'Send an item and a battery of typed questions; route on the answers' },
|
|
50
|
+
{ name: 'List Lanes', value: 'lanes', action: 'List gateway lanes and spend', description: 'Taifoon gateway only: models, trial calls left, licence and spend' },
|
|
51
|
+
{ name: 'Translate', value: 'translate', action: 'Translate a task into typed questions', description: 'Compile a plain-language task into questions. Runs inside the node: free, offline, deterministic.' },
|
|
52
|
+
] },
|
|
53
|
+
{ displayName: 'Connection', name: 'connection', type: 'options', default: 'direct', displayOptions: { show: { operation: ['ask', 'lanes'] } },
|
|
54
|
+
options: [
|
|
55
|
+
{ name: 'Direct to TypeSafe', value: 'direct', description: 'Your own TypeSafe key. No other account needed.' },
|
|
56
|
+
{ name: 'Free Trial (3 Calls, No Key)', value: 'trial', description: 'Three real answers with no account and no key, paid for by Taifoon. Up to 4 questions and 4,000 characters per call.' },
|
|
57
|
+
{ name: 'Taifoon Gateway', value: 'taifoon', description: 'Three free trial calls, then a licence plus your own key. Metered, and adds open-weights models.' },
|
|
58
|
+
] },
|
|
59
|
+
{ displayName: 'Model', name: 'model', type: 'options', default: 'jev', displayOptions: { show: { operation: ['ask'], connection: ['taifoon'] } },
|
|
60
|
+
options: [
|
|
61
|
+
{ name: 'Auditor 27B (Open Weights, Slow)', value: 'auditor', description: 'Reasoning model, about a minute per call; yes/no and pick-one only' },
|
|
62
|
+
{ name: 'Jev (TypeSafe System One)', value: 'jev', description: 'Calibrated probabilities in under a second' },
|
|
63
|
+
{ name: 'Nemotron 4B (Open Weights)', value: 'algotrada', description: 'Yes/no and pick-one on flat symbolic state. On our benchmark it did not read the state: offered for completeness.' },
|
|
64
|
+
] },
|
|
65
|
+
{ displayName: 'Item to Judge', name: 'state', type: 'json', default: '={{ JSON.stringify($json) }}', required: true, displayOptions: { show: { operation: ['ask'] } },
|
|
66
|
+
description: 'Any JSON or text. The default sends the whole incoming item. Do the arithmetic upstream: the model judges, it does not calculate.' },
|
|
67
|
+
{ displayName: 'Questions', name: 'questions', type: 'fixedCollection', typeOptions: { multipleValues: true }, default: {}, placeholder: 'Add Question', displayOptions: { show: { operation: ['ask'] } },
|
|
68
|
+
description: 'Ask every question that might matter in one call: they are answered in parallel and in isolation, so ten cost about what one does',
|
|
69
|
+
options: [{ name: 'question', displayName: 'Question', values: [
|
|
70
|
+
{ displayName: 'ID', name: 'id', type: 'string', default: '', placeholder: 'is_refund', description: 'Lower-case name the answer is returned under' },
|
|
71
|
+
{ displayName: 'Levels', name: 'levels', type: 'string', default: '', placeholder: 'None | Low | Medium | High', displayOptions: { show: { kind: ['score'] } }, description: 'Pipe-separated rubric, lowest first, 2 to 10 levels' },
|
|
72
|
+
{ displayName: 'Options', name: 'options', type: 'string', default: '', placeholder: 'billing, technical, sales, abuse', displayOptions: { show: { kind: ['choice'] } }, description: 'Comma-separated, 2 to 50' },
|
|
73
|
+
{ displayName: 'Question Text', name: 'text', type: 'string', default: '', description: 'One atomic question. Anything that weighs several factors should be several questions.' },
|
|
74
|
+
{ displayName: 'Type', name: 'kind', type: 'options', default: 'noul', options: [
|
|
75
|
+
{ name: 'Choice (Pick One of a Set)', value: 'choice' }, { name: 'Noul (Yes/No as a Probability)', value: 'noul' }, { name: 'Score (Level on a Rubric)', value: 'score' }
|
|
76
|
+
] },
|
|
77
|
+
] }] },
|
|
78
|
+
{ displayName: 'Questions From Translate (JSON)', name: 'questionsJson', type: 'json', default: '[]', displayOptions: { show: { operation: ['ask'] } },
|
|
79
|
+
description: 'Optional. The "questions" array produced by the Translate operation, for example {{ $JSON.ask.questions }}. Added to the questions above.' },
|
|
80
|
+
{ displayName: 'Routing (JSON)', name: 'routing', type: 'json', default: '{}', displayOptions: { show: { operation: ['ask'] } },
|
|
81
|
+
description: 'Thresholds per question ID, for example {"is_refund": {"gte": 0.7}, "team": {"minConfidence": 0.6}}. Items leave by Pass, Fail or Review. Empty: everything leaves by Pass.' },
|
|
82
|
+
{ displayName: 'Task', name: 'task', type: 'string', typeOptions: { rows: 4 }, default: '', placeholder: 'Check if the customer wants a refund. Classify the ticket into billing, technical, sales or abuse. Rate the urgency from 1 to 5.', displayOptions: { show: { operation: ['translate'] } },
|
|
83
|
+
description: 'What to decide, in plain language. One sentence or list item per decision.' },
|
|
84
|
+
{ displayName: 'Language', name: 'language', type: 'options', default: 'auto', displayOptions: { show: { operation: ['translate'] } },
|
|
85
|
+
description: 'The language the task is written in. Auto detects it per sentence, so a mixed task works.',
|
|
86
|
+
options: [
|
|
87
|
+
{ name: 'Arabic', value: 'ar' }, { name: 'Auto-Detect', value: 'auto' }, { name: 'Dutch', value: 'nl' }, { name: 'English', value: 'en' }, { name: 'French', value: 'fr' }, { name: 'German', value: 'de' },
|
|
88
|
+
{ name: 'Italian', value: 'it' }, { name: 'Japanese', value: 'ja' }, { name: 'Polish', value: 'pl' }, { name: 'Portuguese', value: 'pt' }, { name: 'Russian', value: 'ru' }, { name: 'Spanish', value: 'es' }
|
|
89
|
+
] },
|
|
90
|
+
{ displayName: 'Fail Closed', name: 'failClosed', type: 'boolean', default: true, displayOptions: { show: { operation: ['ask'] } },
|
|
91
|
+
description: 'Whether an answer that did not validate stops the item with an error instead of flowing on as a null' },
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
async execute() {
|
|
96
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
97
|
+
const items = this.getInputData();
|
|
98
|
+
const pass = [];
|
|
99
|
+
const fail = [];
|
|
100
|
+
const review = [];
|
|
101
|
+
for (let i = 0; i < items.length; i++) {
|
|
102
|
+
try {
|
|
103
|
+
const operation = this.getNodeParameter('operation', i);
|
|
104
|
+
if (operation === 'translate') {
|
|
105
|
+
const pinned = this.getNodeParameter('language', i, 'auto');
|
|
106
|
+
const { questions, dropped, notes, langs } = (0, translate_1.translateTask)(String((_a = this.getNodeParameter('task', i)) !== null && _a !== void 0 ? _a : ''), 8, pinned === 'auto' ? undefined : pinned);
|
|
107
|
+
const runnable = questions.filter((q) => !q.needs_input);
|
|
108
|
+
pass.push({ pairedItem: { item: i }, json: {
|
|
109
|
+
ready: questions.length > 0 && runnable.length === questions.length, deterministic: true, languages: langs, questions, dropped, notes,
|
|
110
|
+
ask: { questions: runnable.map((q) => ({ id: q.id, kind: q.kind, text: q.text, ...(q.options ? { options: q.options.join(', ') } : {}), ...(q.levels ? { levels: q.levels.join(' | ') } : {}) })),
|
|
111
|
+
routing: {} },
|
|
112
|
+
suggestedRouting: Object.fromEntries(runnable.map((q) => [q.id, q.routing])),
|
|
113
|
+
routingNote: 'Copy only the entries you want to gate on into Routing. A score is a ZERO-BASED level index (0 = your first level); see each answer\'s legend.'
|
|
114
|
+
} });
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const connection = this.getNodeParameter('connection', i);
|
|
118
|
+
if (operation === 'lanes') {
|
|
119
|
+
if (connection !== 'taifoon')
|
|
120
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'List Lanes needs the Taifoon Gateway connection', { itemIndex: i });
|
|
121
|
+
const cred = await this.getCredentials('taifoonGatewayApi');
|
|
122
|
+
const base = String(cred.deckUrl || 'https://deck.taifoon.dev').replace(/\/$/, '');
|
|
123
|
+
pass.push({ json: (await this.helpers.httpRequestWithAuthentication.call(this, 'taifoonGatewayApi', { method: 'GET', url: `${base}/api/typed`, json: true })), pairedItem: { item: i } });
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const stateRaw = this.getNodeParameter('state', i);
|
|
127
|
+
let state = stateRaw;
|
|
128
|
+
if (typeof stateRaw === 'string') {
|
|
129
|
+
try {
|
|
130
|
+
state = JSON.parse(stateRaw);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
state = stateRaw;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const ui = (_b = this.getNodeParameter('questions', i).question) !== null && _b !== void 0 ? _b : [];
|
|
137
|
+
const extraRaw = this.getNodeParameter('questionsJson', i, '[]');
|
|
138
|
+
const extra = (typeof extraRaw === 'string' ? JSON.parse(extraRaw || '[]') : extraRaw);
|
|
139
|
+
const qs = [...ui, ...(Array.isArray(extra) ? extra : [])].filter((q) => (q === null || q === void 0 ? void 0 : q.id) && (q === null || q === void 0 ? void 0 : q.text));
|
|
140
|
+
if (!qs.length)
|
|
141
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Add at least one question', { itemIndex: i });
|
|
142
|
+
const routingRaw = this.getNodeParameter('routing', i, '{}');
|
|
143
|
+
const routing = (typeof routingRaw === 'string' ? JSON.parse(routingRaw || '{}') : routingRaw);
|
|
144
|
+
let answers = [];
|
|
145
|
+
let meta = {};
|
|
146
|
+
if (connection === 'direct') {
|
|
147
|
+
const cred = await this.getCredentials('typeSafeApi');
|
|
148
|
+
const questions = {};
|
|
149
|
+
for (const q of qs) {
|
|
150
|
+
questions[q.id] = q.kind === 'choice' ? { type: 'choice', instructions: q.text, criteria: Object.fromEntries(split(q.options, /\s*,\s*/).map((o) => [o, o])) }
|
|
151
|
+
: q.kind === 'score' ? { type: 'score', instructions: q.text, criteria: split(q.levels, /\s*\|\s*/) }
|
|
152
|
+
: { type: 'noul', instructions: q.text };
|
|
153
|
+
}
|
|
154
|
+
const req = { method: 'POST', url: `${String(cred.baseUrl || 'https://api.typesafe.ai').replace(/\/$/, '')}/v1/systemone`, body: { model: 'jev-latest', state, questions }, json: true, timeout: 60000 };
|
|
155
|
+
const started = Date.now();
|
|
156
|
+
const res = (await withBackoff(() => this.helpers.httpRequestWithAuthentication.call(this, 'typeSafeApi', req)));
|
|
157
|
+
answers = qs.map((q) => {
|
|
158
|
+
var _a, _b, _c, _d, _e, _f;
|
|
159
|
+
const a = ((_a = res.answers) !== null && _a !== void 0 ? _a : {})[q.id];
|
|
160
|
+
if (!a)
|
|
161
|
+
return { id: q.id, kind: q.kind, schema_ok: false, value: null };
|
|
162
|
+
if (q.kind === 'noul')
|
|
163
|
+
return { id: q.id, kind: q.kind, schema_ok: typeof a.noul === 'number', p: (_b = a.noul) !== null && _b !== void 0 ? _b : null, value: typeof a.noul === 'number' ? a.noul >= 0.5 : null };
|
|
164
|
+
if (q.kind === 'choice')
|
|
165
|
+
return { id: q.id, kind: q.kind, schema_ok: typeof a.choice === 'string', value: (_c = a.choice) !== null && _c !== void 0 ? _c : null, confidence: (_d = a.confidence) !== null && _d !== void 0 ? _d : null, probabilities: a.probabilities };
|
|
166
|
+
return { id: q.id, kind: q.kind, schema_ok: typeof a.score === 'number', value: (_e = a.score) !== null && _e !== void 0 ? _e : null, confidence: (_f = a.confidence) !== null && _f !== void 0 ? _f : null, probabilities: a.probabilities, legend: a.legend };
|
|
167
|
+
});
|
|
168
|
+
meta = { model: (_c = res.model) !== null && _c !== void 0 ? _c : 'jev-latest', provider: 'typesafe', connection, latency_ms: Date.now() - started, usage: (_d = res.usage) !== null && _d !== void 0 ? _d : {} };
|
|
169
|
+
}
|
|
170
|
+
else if (connection === 'trial') {
|
|
171
|
+
const res = await askTrial(this, { state: state, questions: qs.map((q) => ({ id: q.id, kind: q.kind, text: q.text,
|
|
172
|
+
...(q.kind === 'choice' ? { options: split(q.options, /\s*,\s*/) } : {}), ...(q.kind === 'score' ? { levels: split(q.levels, /\s*\|\s*/) } : {}) })) });
|
|
173
|
+
answers = (_e = res.answers) !== null && _e !== void 0 ? _e : [];
|
|
174
|
+
meta = { model: res.model, provider: 'typesafe', connection, latency_ms: res.latency_ms, usage: res.usage, trial: res.trial, next: res.next };
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
const cred = await this.getCredentials('taifoonGatewayApi');
|
|
178
|
+
const base = String(cred.deckUrl || 'https://deck.taifoon.dev').replace(/\/$/, '');
|
|
179
|
+
const model = this.getNodeParameter('model', i);
|
|
180
|
+
const body = { model, state, questions: qs.map((q) => ({ id: q.id, kind: q.kind, text: q.text,
|
|
181
|
+
...(q.kind === 'choice' ? { options: split(q.options, /\s*,\s*/) } : {}), ...(q.kind === 'score' ? { levels: split(q.levels, /\s*\|\s*/) } : {}) })) };
|
|
182
|
+
const res = (await withBackoff(() => this.helpers.httpRequestWithAuthentication.call(this, 'taifoonGatewayApi', { method: 'POST', url: `${base}/api/typed`, body, json: true, timeout: 120000 })));
|
|
183
|
+
answers = (_f = res.answers) !== null && _f !== void 0 ? _f : [];
|
|
184
|
+
meta = { model: res.model, provider: (_g = res.provider) !== null && _g !== void 0 ? _g : 'taifoon', connection, latency_ms: res.latency_ms, usage: (_h = res.usage) !== null && _h !== void 0 ? _h : res.tokens, funding: res.funding, cost_usd: res.cost_usd };
|
|
185
|
+
}
|
|
186
|
+
const schemaOk = answers.every((a) => a.schema_ok !== false);
|
|
187
|
+
if (this.getNodeParameter('failClosed', i) && !schemaOk) {
|
|
188
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'An answer did not validate; failing closed', { itemIndex: i, description: JSON.stringify(answers.filter((a) => a.schema_ok === false).map((a) => a.id)) });
|
|
189
|
+
}
|
|
190
|
+
const routed = Object.keys(routing).length ? (0, translate_1.decide)(answers, routing) : null;
|
|
191
|
+
const byId = {};
|
|
192
|
+
for (const a of answers)
|
|
193
|
+
byId[a.id] = a;
|
|
194
|
+
const out = { pairedItem: { item: i }, json: { ...meta, schema_ok: schemaOk, answers: byId,
|
|
195
|
+
...(routed ? { decisions: routed.decisions, allPass: routed.allPass, branch: routed.branch } : { branch: 'pass' }) } };
|
|
196
|
+
((routed === null || routed === void 0 ? void 0 : routed.branch) === 'fail' ? fail : (routed === null || routed === void 0 ? void 0 : routed.branch) === 'review' ? review : pass).push(out);
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
if (this.continueOnFail()) {
|
|
200
|
+
review.push({ json: { error: String((_j = error.message) !== null && _j !== void 0 ? _j : 'request failed').replace(/(apikey_|tfn_live_|Bearer\s+)[A-Za-z0-9_.-]+/g, '$1[redacted]'), branch: 'review' }, pairedItem: { item: i } });
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (error instanceof n8n_workflow_1.NodeOperationError)
|
|
204
|
+
throw error;
|
|
205
|
+
const e = error;
|
|
206
|
+
const status = (_m = (_k = e.httpCode) !== null && _k !== void 0 ? _k : (_l = e.response) === null || _l === void 0 ? void 0 : _l.status) !== null && _m !== void 0 ? _m : 'unknown';
|
|
207
|
+
const said = typeof ((_o = e.response) === null || _o === void 0 ? void 0 : _o.data) === 'object' && ((_p = e.response) === null || _p === void 0 ? void 0 : _p.data) !== null ? JSON.stringify(e.response.data).slice(0, 300) : String((_q = e.description) !== null && _q !== void 0 ? _q : '').slice(0, 300);
|
|
208
|
+
throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: `Request failed (${status})`, description: said.replace(/(apikey_|tfn_live_|Bearer\s+)[A-Za-z0-9_.-]+/g, '$1[redacted]') }, { itemIndex: i, httpCode: String(status) });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return [pass, fail, review];
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
exports.TaifoonTypeSafe = TaifoonTypeSafe;
|
|
215
|
+
//# sourceMappingURL=TaifoonTypeSafe.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaifoonTypeSafe.node.js","sourceRoot":"","sources":["../../../nodes/TaifoonTypeSafe/TaifoonTypeSafe.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "node": "n8n-nodes-taifoon-typesafe.taifoonTypeSafe", "nodeVersion": "1.0", "codexVersion": "1.0", "categories": ["AI", "Data & Storage"], "resources": { "primaryDocumentation": [{ "url": "https://docs.typesafe.ai/introduction" }] } }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60"><rect width="60" height="60" rx="12" fill="#0d0f12"/><path d="M14 20h32M14 30h20M14 40h26" stroke="#7cc4ff" stroke-width="4" stroke-linecap="round"/><circle cx="46" cy="30" r="4" fill="#5fd39a"/></svg>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export type Kind = "noul" | "choice" | "score";
|
|
2
|
+
export interface Compiled {
|
|
3
|
+
id: string;
|
|
4
|
+
kind: Kind;
|
|
5
|
+
text: string;
|
|
6
|
+
options?: string[];
|
|
7
|
+
levels?: string[];
|
|
8
|
+
lang?: string;
|
|
9
|
+
explain: string;
|
|
10
|
+
needs_input?: string;
|
|
11
|
+
routing: Route;
|
|
12
|
+
}
|
|
13
|
+
export interface Route {
|
|
14
|
+
gte?: number;
|
|
15
|
+
lte?: number;
|
|
16
|
+
minConfidence?: number;
|
|
17
|
+
in?: string[];
|
|
18
|
+
min?: number;
|
|
19
|
+
max?: number;
|
|
20
|
+
}
|
|
21
|
+
export type Lang = "en" | "es" | "de" | "fr" | "pt" | "it" | "pl" | "nl" | "ru" | "ja" | "ar";
|
|
22
|
+
export declare const LANGS: Lang[];
|
|
23
|
+
export declare function detectLang(clause: string, hint?: Lang): Lang;
|
|
24
|
+
export declare function clauses(task: string): string[];
|
|
25
|
+
export declare function extractOptions(clause: string, lang?: Lang): string[];
|
|
26
|
+
export declare function translateTask(task: string, maxQuestions?: number, lang?: Lang): {
|
|
27
|
+
questions: Compiled[];
|
|
28
|
+
dropped: number;
|
|
29
|
+
notes: string[];
|
|
30
|
+
langs: Lang[];
|
|
31
|
+
};
|
|
32
|
+
export interface AnswerLike {
|
|
33
|
+
id: string;
|
|
34
|
+
kind: string;
|
|
35
|
+
schema_ok?: boolean;
|
|
36
|
+
p?: number | null;
|
|
37
|
+
value?: unknown;
|
|
38
|
+
confidence?: number | null;
|
|
39
|
+
}
|
|
40
|
+
export interface Decision {
|
|
41
|
+
id: string;
|
|
42
|
+
outcome: "pass" | "fail" | "review";
|
|
43
|
+
reason: string;
|
|
44
|
+
}
|
|
45
|
+
export declare function decide(answers: AnswerLike[], routing: Record<string, Route>): {
|
|
46
|
+
decisions: Decision[];
|
|
47
|
+
allPass: boolean;
|
|
48
|
+
branch: "pass" | "fail" | "review";
|
|
49
|
+
};
|