@taifoon/jev 0.2.1 → 0.2.2
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/docs/WORKFLOWS.md +4 -4
- package/package.json +1 -1
- package/workflows/{0.2.1 → 0.2.2}/README.md +3 -2
- package/workflows/{0.2.1 → 0.2.2}/hire-judge-settle.json +55 -4
- package/workflows/{0.2.1 → 0.2.2}/manifest.json +4 -4
- /package/workflows/{0.2.1 → 0.2.2}/batch-judge.json +0 -0
- /package/workflows/{0.2.1 → 0.2.2}/jev-grader.json +0 -0
- /package/workflows/{0.2.1 → 0.2.2}/schemas/answers.json +0 -0
- /package/workflows/{0.2.1 → 0.2.2}/schemas/common.json +0 -0
- /package/workflows/{0.2.1 → 0.2.2}/schemas/delivery.json +0 -0
- /package/workflows/{0.2.1 → 0.2.2}/schemas/facts.json +0 -0
- /package/workflows/{0.2.1 → 0.2.2}/schemas/hire.json +0 -0
- /package/workflows/{0.2.1 → 0.2.2}/schemas/job.json +0 -0
- /package/workflows/{0.2.1 → 0.2.2}/schemas/settlement.json +0 -0
- /package/workflows/{0.2.1 → 0.2.2}/schemas/verdict.json +0 -0
- /package/workflows/{0.2.1 → 0.2.2}/stamp-grade.json +0 -0
package/docs/WORKFLOWS.md
CHANGED
|
@@ -13,8 +13,8 @@ The node outputs the receipt and the unsigned calls, and it signs nothing. With
|
|
|
13
13
|
|
|
14
14
|
## Workflows
|
|
15
15
|
|
|
16
|
-
`workflows/0.2.
|
|
17
|
-
GitHub release as `jev-workflows-0.2.
|
|
16
|
+
`workflows/0.2.2/` holds the four n8n workflows that run Jev. The same files are attached to the
|
|
17
|
+
GitHub release as `jev-workflows-0.2.2.zip`:
|
|
18
18
|
|
|
19
19
|
- **`hire-judge-settle.json`** runs hire → prepare (facts) → TypeSafe (the four RUBRIC_v1 questions) → answers
|
|
20
20
|
(verdict, recorded and anchored) → settle on devnet. Executions 86 and 88 of this workflow are the golden runs above.
|
|
@@ -24,8 +24,8 @@ GitHub release as `jev-workflows-0.2.1.zip`:
|
|
|
24
24
|
|
|
25
25
|
Credential references are placeholders: `{ "id": "", "name": "REPLACE: <credential type>" }`. After import, pick your
|
|
26
26
|
own credential of that type. Each step names the entity it takes and emits by `$id` (`meta.taifoon.steps`). The schemas
|
|
27
|
-
behind those `$id`s are in `workflows/0.2.
|
|
28
|
-
`workflows/0.2.
|
|
27
|
+
behind those `$id`s are in `workflows/0.2.2/schemas/`. `manifest.json` pins every file by sha256.
|
|
28
|
+
`workflows/0.2.2/README.md` explains each workflow step by step and lists the nodes and credentials it needs:
|
|
29
29
|
|
|
30
30
|
- `@taifoon/n8n-nodes-typesafe`, tested with 1.3.0, is on npm.
|
|
31
31
|
- `n8n-nodes-taifoon`, tested with 0.4.2, and `n8n-nodes-taifoon-devnet-signer`, tested with 0.2.0, are custom
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taifoon/jev",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Grade AI agent jobs with TypeSafe's Jev and record the verdict on chain: code checks the facts, Jev answers a published rubric, and you get a receipt, the on-chain record and the evaluator call for ERC-8183 and Virtuals ACP. No runtime dependencies, no key inside.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jev",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Jev workflows 0.2.
|
|
1
|
+
# Jev workflows 0.2.2
|
|
2
2
|
|
|
3
3
|
The n8n workflows that run Jev on n8n.taifoon.dev, exported with credential references replaced by placeholders (`{ "id": "", "name": "REPLACE: <credential type>" }`: pick your own credential of that type after import). Import with n8n → Workflows → Import from File, or `n8n import:workflow --input=<file>`. Every step carries its contract: `meta.taifoon.steps` names the canonical entity it takes and emits by `$id`; the schemas are in `schemas/` (the `$id`s are identifiers, the files are here).
|
|
4
4
|
|
|
@@ -22,7 +22,7 @@ The n8n workflows that run Jev on n8n.taifoon.dev, exported with credential refe
|
|
|
22
22
|
|
|
23
23
|
One hire from offer to settlement. The seller’s reply is held with its digest; prepare decides the facts (a hard fail skips Jev); your TypeSafe credential answers the four RUBRIC_v1 questions; answers composes the verdict under THRESHOLDS_v1, records decision.v2 and jev.answer.v1 and anchors them on the devnet logs; a complete settles through the devnet assurance hook (approve, fund, submit, complete), needs_review is held. Executions 86 and 88 of this workflow are the golden runs @taifoon/jev re-derives.
|
|
24
24
|
|
|
25
|
-
- source: `tfnhiresettle001` on n8n.taifoon.dev · sha256 `
|
|
25
|
+
- source: `tfnhiresettle001` on n8n.taifoon.dev · sha256 `7053740d120a0d46a0e35ce75194b8529579d353f83a081e80c58dcb663f0958`
|
|
26
26
|
- nodes: `n8n-nodes-taifoon`, `@taifoon/n8n-nodes-typesafe`, `n8n-nodes-taifoon-devnet-signer`; built-ins manualTrigger v1, set v3.4, code v2, if v2.2
|
|
27
27
|
- credentials: `taifoonRelayerApi`, `taifoonTypeSafeApi`, `taifoonDevnetKeyApi`
|
|
28
28
|
|
|
@@ -45,6 +45,7 @@ One hire from offer to settlement. The seller’s reply is held with its digest;
|
|
|
45
45
|
| Buyer · complete + capture | settlement.json | settlement.json | complete(jobId) (+ capture): machine → Settled |
|
|
46
46
|
| Held for review | settlement.json | settlement.json | needs_review / reject: funded and sealed, nothing paid; the evaluator leg or the deadline decides |
|
|
47
47
|
| Receipt | settlement.json | job.json | the whole JOB: hire, delivery, facts, verdict, settlement — every transaction with its proof link |
|
|
48
|
+
| Proofs · wait | job.json | job.json | GET /v1/proof/tx/36927/<tx> for every transaction of the run; pending is retried with backoff (5 s -> 60 s, <= 240 s), never reported as a gap |
|
|
48
49
|
|
|
49
50
|
## Jev on-chain grader (grade → stamp → devnet) — `jev-grader.json`
|
|
50
51
|
|
|
@@ -51,13 +51,13 @@
|
|
|
51
51
|
{
|
|
52
52
|
"id": "i6",
|
|
53
53
|
"name": "buyer",
|
|
54
|
-
"value": "
|
|
54
|
+
"value": "0xf6806EFcb34dDa2eE78967384D09367ECd364483",
|
|
55
55
|
"type": "string"
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
"id": "i7",
|
|
59
59
|
"name": "seller",
|
|
60
|
-
"value": "
|
|
60
|
+
"value": "0xe6209aD65a66d5eF11E00A7B33Cd21ce7084715c",
|
|
61
61
|
"type": "string"
|
|
62
62
|
},
|
|
63
63
|
{
|
|
@@ -71,6 +71,24 @@
|
|
|
71
71
|
"name": "chainId",
|
|
72
72
|
"value": 36927,
|
|
73
73
|
"type": "number"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "i10",
|
|
77
|
+
"name": "lane",
|
|
78
|
+
"value": "a",
|
|
79
|
+
"type": "string"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": "i11",
|
|
83
|
+
"name": "tenant",
|
|
84
|
+
"value": "",
|
|
85
|
+
"type": "string"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"id": "i12",
|
|
89
|
+
"name": "deadline_sec",
|
|
90
|
+
"value": 300,
|
|
91
|
+
"type": "number"
|
|
74
92
|
}
|
|
75
93
|
]
|
|
76
94
|
},
|
|
@@ -286,7 +304,9 @@
|
|
|
286
304
|
"refId": "={{ $json.handshake_id }}",
|
|
287
305
|
"settleOptions": {
|
|
288
306
|
"endpoint": "={{ $json.endpoint }}",
|
|
289
|
-
"note": "={{ 'agent ' + $json.candidate + ' · decision ' + ($json.decision_id || 'none') + ' · verdict ' + ($json.verdict || 'n/a') }}"
|
|
307
|
+
"note": "={{ 'agent ' + $json.candidate + ' · decision ' + ($json.decision_id || 'none') + ' · verdict ' + ($json.verdict || 'n/a') }}",
|
|
308
|
+
"tenant": "={{ $json.tenant }}",
|
|
309
|
+
"deadline": "={{ Math.floor(Date.now() / 1000) + Number($json.deadline_sec || 3600) }}"
|
|
290
310
|
}
|
|
291
311
|
},
|
|
292
312
|
"credentials": {
|
|
@@ -408,7 +428,7 @@
|
|
|
408
428
|
},
|
|
409
429
|
{
|
|
410
430
|
"parameters": {
|
|
411
|
-
"jsCode": "// The record: every transaction with its proof and explorer link, the decision, the job, and whether money moved.\nconst legs = ['Seller · approve deposit', 'Buyer · approve + fund', 'Seller · submit', 'Buyer · complete + capture'];\nconst txs = [];\nfor (const n of legs) { let sent = []; try { sent = $(n).first().json.sent || []; } catch (e) { /* a leg the verdict skipped */ }\n for (const s of sent) txs.push({ leg: n, action: s.action, tx: s.tx, status: s.status, block: s.block, proof: 'https://www.taifoon.io/v1/proof/tx/36927/' + s.tx, scan: 'https://www.taifoon.io/scan/36927/tx/' + s.tx }); }\nlet held = null; try { held = $('Held for review').first().json; } catch (e) { held = null; }\nconst s = $('Settle').first().json;\nconst v = $('Verdict').first().json;\nconst complete = txs.find((t) => t.action === 'complete') || null;\nreturn [{ json: { handshake_id: v.handshake_id, decision_id: v.decision_id, decision_digest: v.decision_digest, decision_anchor_tx: v.decision_anchor ? v.decision_anchor.tx : null, verdict: v.verdict, verdict_auto: v.verdict_auto, reasons: v.reasons, receipt_hash: v.receipt_hash, judge: { called: v.judge_called, model: v.model, latency_ms: v.judge_latency_ms, answers_source: v.answers_source, execution: v.execution, prepare_digest: v.prepare_digest, quota: v.quota }, ending: complete ? 'completed: seller paid, deposit returned, payment captured' : held ? 'held: ' + held.next : 'incomplete', jobId: s.jobId, correlator: s.correlator, chainId: 36927, hook: s.hook, token: s.token, price: s.price, premium: s.premium, deposit: s.deposit, evidence: v.evidence, settlement_tx: complete ? complete.tx : null, settlement_proof: complete ? complete.proof : null, transactions: txs, all_mined: txs.every((t) => t.status === 'success') && txs.length === (complete ? 6 : 4) } }];"
|
|
431
|
+
"jsCode": "// The record: every transaction with its proof and explorer link, the decision, the job, and whether money moved.\nconst legs = ['Seller · approve deposit', 'Buyer · approve + fund', 'Seller · submit', 'Buyer · complete + capture'];\nconst txs = [];\nfor (const n of legs) { let sent = []; try { sent = $(n).first().json.sent || []; } catch (e) { /* a leg the verdict skipped */ }\n for (const s of sent) txs.push({ leg: n, action: s.action, tx: s.tx, status: s.status, block: s.block, proof: 'https://www.taifoon.io/v1/proof/tx/36927/' + s.tx, scan: 'https://www.taifoon.io/scan/36927/tx/' + s.tx }); }\nlet held = null; try { held = $('Held for review').first().json; } catch (e) { held = null; }\nconst s = $('Settle').first().json;\nconst v = $('Verdict').first().json;\nconst complete = txs.find((t) => t.action === 'complete') || null;\nreturn [{ json: { handshake_id: v.handshake_id, decision_id: v.decision_id, decision_digest: v.decision_digest, decision_anchor_tx: v.decision_anchor ? v.decision_anchor.tx : null, verdict: v.verdict, verdict_auto: v.verdict_auto, reasons: v.reasons, receipt_hash: v.receipt_hash, judge: { called: v.judge_called, model: v.model, latency_ms: v.judge_latency_ms, answers_source: v.answers_source, execution: v.execution, prepare_digest: v.prepare_digest, quota: v.quota }, ending: complete ? 'completed: seller paid, deposit returned, payment captured' : held ? 'held: ' + held.next : 'incomplete', lane: v.lane || null, tenant: s.tenant || null, deadline: s.deadline ?? null, jobId: s.jobId, correlator: s.correlator, chainId: 36927, hook: s.hook, token: s.token, price: s.price, premium: s.premium, deposit: s.deposit, evidence: v.evidence, settlement_tx: complete ? complete.tx : null, settlement_proof: complete ? complete.proof : null, transactions: txs, all_mined: txs.every((t) => t.status === 'success') && txs.length === (complete ? 6 : 4) } }];"
|
|
412
432
|
},
|
|
413
433
|
"id": "n11",
|
|
414
434
|
"name": "Receipt",
|
|
@@ -470,6 +490,21 @@
|
|
|
470
490
|
],
|
|
471
491
|
"notes": "in: settlement.json → out: settlement.json · needs_review / reject: funded and sealed, nothing paid; the evaluator leg or the deadline decides",
|
|
472
492
|
"notesInFlow": true
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
"parameters": {
|
|
496
|
+
"jsCode": "// Every transaction of the run is proven under the V5 superroot before the run ends (/v1/proof/tx/36927/<tx>).\n// The producer runs ~6-8 devnet blocks (~15 s) behind the head, and its blob route can answer \"pending\" under load:\n// a pending answer is waited out with backoff (5 s doubling to 60 s), never reported as a gap. The wait is capped at\n// 240 s (n8n's task-runner limit); what is still pending is listed, and the runner (workflows/e2e.sh) keeps waiting.\nconst r = $input.first().json;\nconst SITE = 'https://www.taifoon.io';\nconst txs = [...(r.transactions || []).map((t) => ({ leg: t.leg, action: t.action, tx: t.tx })), ...(r.decision_anchor_tx ? [{ leg: 'decision anchor', action: 'JevDecisionLog.record', tx: r.decision_anchor_tx }] : [])];\nconst until = Date.now() + 240000;\nconst sleep = (ms) => new Promise((res) => setTimeout(res, ms));\nconst final = (c) => Boolean(c && c.proof_served && c.block_hash_matches && c.within_verifiable_range);\nconst proofs = [];\nfor (const t of txs) {\n let wait = 5000, attempts = 0, last = null;\n for (;;) {\n attempts++;\n try { last = await this.helpers.httpRequest({ method: 'GET', url: SITE + '/v1/proof/tx/36927/' + t.tx + (attempts > 3 ? '?wait=1' : ''), json: true, timeout: 60000, ignoreHttpStatusErrors: true }); }\n catch (e) { last = { ok: false, error: String((e && e.message) || e).slice(0, 160) }; }\n if (final(last && last.checks)) break;\n if (last && last.code === 'PROVABLE_GAP' && last.gap) break; // the producer skipped this block: no wait fills it\n if (Date.now() + wait > until) break;\n await sleep(wait); wait = Math.min(wait * 2, 60000);\n }\n const c = (last && last.checks) || {};\n proofs.push({ ...t, finalized: final(c), gap: Boolean(last && last.gap), attempts, checks: c, proof: SITE + '/v1/proof/tx/36927/' + t.tx });\n}\nreturn [{ json: { ...r, proofs, all_proven: proofs.length > 0 && proofs.every((p) => p.finalized), proofs_pending: proofs.filter((p) => !p.finalized).map((p) => p.tx) } }];"
|
|
497
|
+
},
|
|
498
|
+
"id": "n17",
|
|
499
|
+
"name": "Proofs · wait",
|
|
500
|
+
"type": "n8n-nodes-base.code",
|
|
501
|
+
"typeVersion": 2,
|
|
502
|
+
"position": [
|
|
503
|
+
3520,
|
|
504
|
+
300
|
|
505
|
+
],
|
|
506
|
+
"notes": "in: job.json → out: job.json · GET /v1/proof/tx/36927/<tx> for every transaction of the run; pending is retried with backoff (5 s -> 60 s, <= 240 s), never reported as a gap",
|
|
507
|
+
"notesInFlow": true
|
|
473
508
|
}
|
|
474
509
|
],
|
|
475
510
|
"connections": {
|
|
@@ -662,6 +697,17 @@
|
|
|
662
697
|
}
|
|
663
698
|
]
|
|
664
699
|
]
|
|
700
|
+
},
|
|
701
|
+
"Receipt": {
|
|
702
|
+
"main": [
|
|
703
|
+
[
|
|
704
|
+
{
|
|
705
|
+
"node": "Proofs · wait",
|
|
706
|
+
"type": "main",
|
|
707
|
+
"index": 0
|
|
708
|
+
}
|
|
709
|
+
]
|
|
710
|
+
]
|
|
665
711
|
}
|
|
666
712
|
},
|
|
667
713
|
"settings": {
|
|
@@ -759,6 +805,11 @@
|
|
|
759
805
|
"in": "https://www.taifoon.io/schemas/coordination/v1/settlement.json",
|
|
760
806
|
"out": "https://www.taifoon.io/schemas/coordination/v1/job.json",
|
|
761
807
|
"does": "the whole JOB: hire, delivery, facts, verdict, settlement — every transaction with its proof link"
|
|
808
|
+
},
|
|
809
|
+
"Proofs · wait": {
|
|
810
|
+
"in": "https://www.taifoon.io/schemas/coordination/v1/job.json",
|
|
811
|
+
"out": "https://www.taifoon.io/schemas/coordination/v1/job.json",
|
|
812
|
+
"does": "GET /v1/proof/tx/36927/<tx> for every transaction of the run; pending is retried with backoff (5 s -> 60 s, <= 240 s), never reported as a gap"
|
|
762
813
|
}
|
|
763
814
|
}
|
|
764
815
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"bundle": "jev-workflows-0.2.
|
|
3
|
-
"package": "@taifoon/jev@0.2.
|
|
2
|
+
"bundle": "jev-workflows-0.2.2",
|
|
3
|
+
"package": "@taifoon/jev@0.2.2",
|
|
4
4
|
"workflows": [
|
|
5
5
|
{
|
|
6
6
|
"file": "hire-judge-settle.json",
|
|
7
7
|
"source_id": "tfnhiresettle001",
|
|
8
8
|
"name": "Taifoon — HIRE → JUDGE → SETTLE (devnet 36927)",
|
|
9
|
-
"sha256": "
|
|
10
|
-
"nodes":
|
|
9
|
+
"sha256": "7053740d120a0d46a0e35ce75194b8529579d353f83a081e80c58dcb663f0958",
|
|
10
|
+
"nodes": 18,
|
|
11
11
|
"packages": [
|
|
12
12
|
"n8n-nodes-taifoon",
|
|
13
13
|
"@taifoon/n8n-nodes-typesafe",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|