@taifoon/jev 0.3.0 → 0.4.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/CHANGELOG.md +32 -0
- package/README.md +100 -13
- package/dist/addresses.d.ts +6 -1
- package/dist/addresses.js +4 -2
- package/dist/attest.js +5 -3
- package/dist/chains.d.ts +4 -0
- package/dist/verify.js +35 -3
- package/package.json +13 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@taifoon/jev`. Versions follow the GitHub releases of this repository; each is published to npm
|
|
4
|
+
with provenance by `.github/workflows/publish.yml`.
|
|
5
|
+
|
|
6
|
+
## 0.4.0
|
|
7
|
+
|
|
8
|
+
- `verify` reads a trusted record past an endpoint that serves only recent logs. `JevAnswerLog.recordedAt` names the block
|
|
9
|
+
of a trusted record; when an endpoint answers `[]` for that block, the next endpoint of the rotation is asked. A record
|
|
10
|
+
reads `not_recorded` only when every endpoint that answered held no row; no answer at all is still `rpc_unavailable`.
|
|
11
|
+
(Seen on Base for a record 1.35M blocks old.) Two tests cover both outcomes.
|
|
12
|
+
- `src/attest.ts`: the defaults of an unknown chain are their own typed value, so the copy compiles under stricter
|
|
13
|
+
TypeScript settings (TS2783). Types only; the calls it returns are unchanged.
|
|
14
|
+
- Taifoon mainnet (3692781) is Jev's record home: `record()` builds the `JevAnswerLog.record` and `JevDecisionLog.record`
|
|
15
|
+
calls for it by default (JevDecisionLog `0xaEbF9084Bb32eB2E0F58537526A8877dd1436b23`, JevAnswerLogV2
|
|
16
|
+
`0xC08dfc61d702AEA45d1EF2515d8BDA36d548C75c`), and `verify --chain taifoon` reads them. It has no GradeStampRegistry
|
|
17
|
+
yet; the stamp is listed under `missing`.
|
|
18
|
+
- Base: answers are written to JevAnswerLogV2 (`0xC08dfc61d702AEA45d1EF2515d8BDA36d548C75c`, from block 52639649).
|
|
19
|
+
`verify` reads V2 first, then the earlier JevAnswerLog (`0x8e9B9cE86a2d55c10318607b0c815B7B8C66254d`), so every
|
|
20
|
+
earlier record still verifies. Two tests cover both logs.
|
|
21
|
+
- README: what you get, how it works, and where Jev's records live.
|
|
22
|
+
- package: CHANGELOG.md ships in the tarball; search keywords.
|
|
23
|
+
|
|
24
|
+
## 0.3.0 (2026-10-14)
|
|
25
|
+
|
|
26
|
+
- Recording is on by default: every grade returns the unsigned `JevAnswerLog.record`, `JevDecisionLog.record` and
|
|
27
|
+
`GradeStampRegistry.stamp` calls for the Taifoon devnet 36927 and the Taifoon mainnet 3692781 (`--record none` turns
|
|
28
|
+
them off; a contract a network does not have is listed in `missing`). One shared attestation helper for the mark, the
|
|
29
|
+
attestation and the stamp.
|
|
30
|
+
- Optional fields of the attestation helper accept `undefined` (`exactOptionalPropertyTypes`).
|
|
31
|
+
|
|
32
|
+
Earlier versions: see the [releases](https://github.com/taifoon-io/jev/releases).
|
package/README.md
CHANGED
|
@@ -1,24 +1,83 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/taifoon-io/jev/main/assets/banner.svg" alt="Jev for agent jobs" width="100%">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/@taifoon/jev"><img src="https://img.shields.io/npm/v/@taifoon/jev?style=flat-square&labelColor=000000&color=3DA5FF&label=npm" alt="npm"></a>
|
|
7
|
+
<a href="https://www.npmjs.com/package/@taifoon/jev#provenance"><img src="https://img.shields.io/badge/provenance-signed-00B5B8?style=flat-square&labelColor=000000" alt="provenance"></a>
|
|
8
|
+
<a href="LICENSE"><img src="https://img.shields.io/npm/l/@taifoon/jev?style=flat-square&labelColor=000000&color=E6F0F7" alt="licence"></a>
|
|
9
|
+
<a href="https://www.npmjs.com/package/@taifoon/jev"><img src="https://img.shields.io/npm/dm/@taifoon/jev?style=flat-square&labelColor=000000&color=3DA5FF" alt="downloads"></a>
|
|
10
|
+
</p>
|
|
2
11
|
|
|
3
12
|
**Did the AI agent do the work it was paid for? Ask Jev, and get an answer you can check.**
|
|
4
13
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- **How:** replay a Base job, graded by Jev, offline and with no key:
|
|
14
|
+
Code checks the facts of the delivery, TypeSafe's Jev answers four closed questions about it, and code turns the answers
|
|
15
|
+
into **complete**, **reject** or **needs review**, with a receipt anyone can recompute, the unsigned calls that record it on
|
|
16
|
+
chain and the one call that ends the job on its protocol (ERC-8183, Virtuals ACP, BitAgent). No key inside, and it signs
|
|
17
|
+
nothing.
|
|
10
18
|
|
|
11
|
-
|
|
19
|
+
## 30 seconds
|
|
20
|
+
|
|
21
|
+
```sh
|
|
12
22
|
npx @taifoon/jev run --demo
|
|
13
23
|
```
|
|
14
24
|
|
|
25
|
+
Offline, no key: replays BitAgent job 7287 on Base as Jev graded it, composes **reject**, and arrives at the decision
|
|
26
|
+
digest that is anchored on chain. Then read a recorded grade back from Base:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
npx @taifoon/jev verify decision-1790522234088-10691d5017 --network base
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
It recomputes the record's digests offline and finds both rows on Base (`"status": "recorded"`).
|
|
33
|
+
|
|
15
34
|

|
|
16
35
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
36
|
+
## What you get
|
|
37
|
+
|
|
38
|
+
| | |
|
|
39
|
+
|---|---|
|
|
40
|
+
| **A verdict with its reasons** | complete, reject or needs review, with every answer's full probability distribution |
|
|
41
|
+
| **A receipt anyone can recompute** | digests of the evidence, the answers and the decision; `verify()` recomputes them offline |
|
|
42
|
+
| **The on-chain record, unsigned** | `JevAnswerLog.record`, `JevDecisionLog.record` and `GradeStampRegistry.stamp` calls for your wallet |
|
|
43
|
+
| **The call that ends the job** | the evaluator call for `assurance-hook`, `judge-adapter`, `virtuals-erc8183`, `virtuals-memo-acp`, `bitagent-erc8183` |
|
|
44
|
+
| **A cover price for the next job** | the seller's premium from its record, through [`@taifoon/jev-wilson`](https://www.npmjs.com/package/@taifoon/jev-wilson) |
|
|
45
|
+
| **No key needed to start** | 3 free grades a day per caller on the Taifoon coordination layer, or your own TypeSafe key |
|
|
46
|
+
|
|
47
|
+
## How it works
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
the job as the buyer wrote it (task, criteria, source, delivered)
|
|
51
|
+
│ prepareJob()
|
|
52
|
+
▼
|
|
53
|
+
code checks the facts ─── a check fails ──▶ reject (Jev is not asked)
|
|
54
|
+
│ all pass
|
|
55
|
+
▼
|
|
56
|
+
Jev answers RUBRIC_v1: spec_met · unsupported_claim · ending · cheat_shaped
|
|
57
|
+
│ grade()
|
|
58
|
+
▼
|
|
59
|
+
code composes THRESHOLDS_v1 ──▶ complete | reject | needs_review + receipt
|
|
60
|
+
│ record() · evaluatorCall()
|
|
61
|
+
▼
|
|
62
|
+
unsigned calls: the answer log, the decision log, the evaluator seat (you sign)
|
|
63
|
+
│ verify()
|
|
64
|
+
▼
|
|
65
|
+
digests recomputed, rows found on chain
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Install
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
npm i @taifoon/jev
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Node.js 20 or later. Installing it also installs Taifoon's other packages (@taifoon/jev-wilson,
|
|
75
|
+
@taifoon/n8n-nodes-typesafe); nothing third-party. Grade with no key on your free grades on the Taifoon coordination layer
|
|
76
|
+
(3 a day per caller), or with your TypeSafe key from [console.typesafe.ai](https://console.typesafe.ai). Every grade comes
|
|
77
|
+
with the unsigned calls that record it on chain (the Taifoon devnet and mainnet by default, any network you name;
|
|
78
|
+
`--record none` turns them off).
|
|
20
79
|
|
|
21
|
-
##
|
|
80
|
+
## Grade your own job
|
|
22
81
|
|
|
23
82
|
An agent was hired for a job. The grader answers one question: did it do the work as the task laid it out? You give
|
|
24
83
|
it the job the way the buyer wrote it, and it does the rest:
|
|
@@ -182,8 +241,30 @@ npx @taifoon/jev workflows export ./jev-workflows
|
|
|
182
241
|
## Chains
|
|
183
242
|
|
|
184
243
|
`verify` reads the Jev logs on every chain they are deployed to: the Taifoon devnet (36927), Base (8453), Arbitrum One
|
|
185
|
-
(42161), Arc (5042) and Monad (143). Robinhood Chain (4663)
|
|
186
|
-
|
|
244
|
+
(42161), Arc (5042) and Monad (143). Robinhood Chain (4663) and Ethereum (1) are known chains with no Jev log; `verify`
|
|
245
|
+
says so instead of reading them.
|
|
246
|
+
|
|
247
|
+
### Where Jev's records live
|
|
248
|
+
|
|
249
|
+
| Chain | JevDecisionLog | JevAnswerLog |
|
|
250
|
+
|---|---|---|
|
|
251
|
+
| Taifoon mainnet (3692781), the record home | `0xaEbF9084Bb32eB2E0F58537526A8877dd1436b23` | `0xC08dfc61d702AEA45d1EF2515d8BDA36d548C75c` (JevAnswerLogV2) |
|
|
252
|
+
| Base (8453) | [`0x209490d6A0FFC5368A42b0c2208BDCda853f6a92`](https://basescan.org/address/0x209490d6A0FFC5368A42b0c2208BDCda853f6a92) | [`0xC08dfc61d702AEA45d1EF2515d8BDA36d548C75c`](https://basescan.org/address/0xC08dfc61d702AEA45d1EF2515d8BDA36d548C75c) (JevAnswerLogV2); earlier records in [`0x8e9B9cE86a2d55c10318607b0c815B7B8C66254d`](https://basescan.org/address/0x8e9B9cE86a2d55c10318607b0c815B7B8C66254d) |
|
|
253
|
+
| Taifoon devnet (36927) | `0x1D622511862DD7DEffB8fEeBc225E0FAdA1e9A05` | `0xD8c1d8188Fc8EE388792f6EB3B3dbd4f341Ba8e3` |
|
|
254
|
+
|
|
255
|
+
The two Taifoon mainnet logs were deployed on 2026-11-08 at their CREATE2 addresses (JevAnswerLogV2 has the same
|
|
256
|
+
address on Base). Taifoon mainnet has no public explorer yet; read them from its public RPC:
|
|
257
|
+
|
|
258
|
+
```sh
|
|
259
|
+
curl -s https://mainnet.taifoon.dev -H 'content-type: application/json' \
|
|
260
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"eth_getCode","params":["0xaEbF9084Bb32eB2E0F58537526A8877dd1436b23","latest"]}'
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
`record()` builds the calls for both logs on Taifoon mainnet by default (next to the devnet), and `verify --chain taifoon`
|
|
264
|
+
reads them. Taifoon mainnet has no GradeStampRegistry yet, so the stamp is listed under `missing` there, said rather
|
|
265
|
+
than faked. On Base, answers are written to JevAnswerLogV2 and `verify` reads it first, then the earlier JevAnswerLog,
|
|
266
|
+
so a record from before V2 still verifies. Base keeps its published JevDecisionLog. Every address above is in
|
|
267
|
+
`src/addresses.ts` and `src/attest.ts`.
|
|
187
268
|
|
|
188
269
|
| Flag | What it does |
|
|
189
270
|
|---|---|
|
|
@@ -213,6 +294,12 @@ it ships (`src/rpc-fallback.ts`, generated from the RPC registry).
|
|
|
213
294
|
In code: `verify(digest, { network: 'arbitrum' })` (a name or a chain id), `{ rpc: 'https://…' }`, and `JevChainError`
|
|
214
295
|
(`code`: `rpc_unavailable`, `not_deployed`, `reverted`, `bad_input`) from the lower-level calls.
|
|
215
296
|
|
|
297
|
+
## Links
|
|
298
|
+
|
|
299
|
+
- npm: [@taifoon/jev](https://www.npmjs.com/package/@taifoon/jev) · pricing: [@taifoon/jev-wilson](https://www.npmjs.com/package/@taifoon/jev-wilson) · n8n: [@taifoon/n8n-nodes-typesafe](https://www.npmjs.com/package/@taifoon/n8n-nodes-typesafe)
|
|
300
|
+
- The coordination layer: [coord.taifoon.dev/v1](https://coord.taifoon.dev/v1) ([OpenAPI](https://coord.taifoon.dev/v1/openapi.json)) · [taifoon.io](https://www.taifoon.io)
|
|
301
|
+
- Changes: [CHANGELOG.md](CHANGELOG.md) · issues: [github.com/taifoon-io/jev/issues](https://github.com/taifoon-io/jev/issues) · contact: info@taifoon.io
|
|
302
|
+
|
|
216
303
|
## Licence
|
|
217
304
|
|
|
218
305
|
Independent project. Jev and TypeSafe are products of TypeSafe AI, Inc., which does not endorse this package.
|
package/dist/addresses.d.ts
CHANGED
|
@@ -60,7 +60,8 @@ export declare const REGISTRY_ADDRESSES: {
|
|
|
60
60
|
readonly block: 48395723;
|
|
61
61
|
};
|
|
62
62
|
};
|
|
63
|
-
/** The Jev logs on every chain the registry deploys them to (
|
|
63
|
+
/** The Jev logs on every chain the registry deploys them to (from their deploy block): the answer log records go to (JevAnswerLogV2
|
|
64
|
+
* where it is live, else JevAnswerLog), the decision log, and the earlier answer logs still read (Base: the first JevAnswerLog). */
|
|
64
65
|
export declare const JEV_LOGS: Readonly<Record<number, {
|
|
65
66
|
answerLog: {
|
|
66
67
|
address: string;
|
|
@@ -70,4 +71,8 @@ export declare const JEV_LOGS: Readonly<Record<number, {
|
|
|
70
71
|
address: string;
|
|
71
72
|
fromBlock: number;
|
|
72
73
|
};
|
|
74
|
+
earlierAnswerLogs?: readonly {
|
|
75
|
+
address: string;
|
|
76
|
+
fromBlock: number;
|
|
77
|
+
}[];
|
|
73
78
|
}>>;
|
package/dist/addresses.js
CHANGED
|
@@ -22,11 +22,13 @@ export const REGISTRY_ADDRESSES = {
|
|
|
22
22
|
/** standards-erc8183 · BitAgent ERC-8183 escrow (live) */
|
|
23
23
|
bitagentErc8183: { chainId: 8453, address: '0x5009ABB3A309115a4a682C66BAf3BC9E0329BaB7', block: 48395723 },
|
|
24
24
|
};
|
|
25
|
-
/** The Jev logs on every chain the registry deploys them to (
|
|
25
|
+
/** The Jev logs on every chain the registry deploys them to (from their deploy block): the answer log records go to (JevAnswerLogV2
|
|
26
|
+
* where it is live, else JevAnswerLog), the decision log, and the earlier answer logs still read (Base: the first JevAnswerLog). */
|
|
26
27
|
export const JEV_LOGS = {
|
|
27
28
|
143: { answerLog: { address: '0x29fEEc116e0CAbbaf38e9EBF2BBf65d82D672104', fromBlock: 110216088 }, decisionLog: { address: '0x1aC6266b9926cB3E206D5dc0c9d1B7c873aa150a', fromBlock: 110216093 } },
|
|
28
29
|
5042: { answerLog: { address: '0x45214361A8cADb8aEe6302cd5653E119E5a89839', fromBlock: 24071071 }, decisionLog: { address: '0x863db7dAc69CC614a98822082cbe884F1f3b55cA', fromBlock: 24071074 } },
|
|
29
|
-
8453: { answerLog: { address: '
|
|
30
|
+
8453: { answerLog: { address: '0xC08dfc61d702AEA45d1EF2515d8BDA36d548C75c', fromBlock: 52639649 }, decisionLog: { address: '0x209490d6A0FFC5368A42b0c2208BDCda853f6a92', fromBlock: 51856200 }, earlierAnswerLogs: [{ address: '0x8e9B9cE86a2d55c10318607b0c815B7B8C66254d', fromBlock: 51863008 }] },
|
|
30
31
|
36927: { answerLog: { address: '0xD8c1d8188Fc8EE388792f6EB3B3dbd4f341Ba8e3', fromBlock: 1106754 }, decisionLog: { address: '0x1D622511862DD7DEffB8fEeBc225E0FAdA1e9A05', fromBlock: 981099 } },
|
|
31
32
|
42161: { answerLog: { address: '0x29fEEc116e0CAbbaf38e9EBF2BBf65d82D672104', fromBlock: 511340178 }, decisionLog: { address: '0x1aC6266b9926cB3E206D5dc0c9d1B7c873aa150a', fromBlock: 511340188 } },
|
|
33
|
+
3692781: { answerLog: { address: '0xC08dfc61d702AEA45d1EF2515d8BDA36d548C75c', fromBlock: 2598386 }, decisionLog: { address: '0xaEbF9084Bb32eB2E0F58537526A8877dd1436b23', fromBlock: 2598383 } },
|
|
32
34
|
};
|
package/dist/attest.js
CHANGED
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
export const ATTEST_TARGETS = {
|
|
23
23
|
143: { name: 'Monad', decisionLog: '0x1aC6266b9926cB3E206D5dc0c9d1B7c873aa150a', answerLog: '0x29fEEc116e0CAbbaf38e9EBF2BBf65d82D672104', stampRegistry: null },
|
|
24
24
|
5042: { name: 'Arc', decisionLog: '0x863db7dAc69CC614a98822082cbe884F1f3b55cA', answerLog: '0x45214361A8cADb8aEe6302cd5653E119E5a89839', stampRegistry: null },
|
|
25
|
-
8453: { name: 'Base', decisionLog: '0x209490d6A0FFC5368A42b0c2208BDCda853f6a92', answerLog: '
|
|
25
|
+
8453: { name: 'Base', decisionLog: '0x209490d6A0FFC5368A42b0c2208BDCda853f6a92', answerLog: '0xC08dfc61d702AEA45d1EF2515d8BDA36d548C75c', stampRegistry: null },
|
|
26
26
|
36927: { name: 'Taifoon devnet', decisionLog: '0x1D622511862DD7DEffB8fEeBc225E0FAdA1e9A05', answerLog: '0xD8c1d8188Fc8EE388792f6EB3B3dbd4f341Ba8e3', stampRegistry: '0xff5B4852AC7066D04FEd8de97bdA52401d03ad6E' },
|
|
27
27
|
42161: { name: 'Arbitrum One', decisionLog: '0x1aC6266b9926cB3E206D5dc0c9d1B7c873aa150a', answerLog: '0x29fEEc116e0CAbbaf38e9EBF2BBf65d82D672104', stampRegistry: null },
|
|
28
|
-
3692781: { name: 'Taifoon mainnet', decisionLog:
|
|
28
|
+
3692781: { name: 'Taifoon mainnet', decisionLog: '0xaEbF9084Bb32eB2E0F58537526A8877dd1436b23', answerLog: '0xC08dfc61d702AEA45d1EF2515d8BDA36d548C75c', stampRegistry: null },
|
|
29
29
|
};
|
|
30
30
|
// ── END GENERATED ──
|
|
31
31
|
/** The default networks per profile. Taifoon: its devnet and its mainnet (GRID). Moonbeam: Base only. */
|
|
@@ -198,7 +198,9 @@ export function attest(input, opts = {}) {
|
|
|
198
198
|
const calls = [];
|
|
199
199
|
const missing = [];
|
|
200
200
|
for (const chainId of networks) {
|
|
201
|
-
|
|
201
|
+
// the defaults as their own value: written inline before a spread of a fully typed target, tsc refuses them (TS2783)
|
|
202
|
+
const unknownChain = { name: `chain ${chainId}`, decisionLog: null, answerLog: null, stampRegistry: null };
|
|
203
|
+
const t = { ...unknownChain, ...ATTEST_TARGETS[chainId], ...opts.targets?.[chainId] };
|
|
202
204
|
const gap = (contract) => missing.push({ chainId, network: t.name, contract, why: `no ${contract} on ${t.name} (${chainId}) in the address registry` });
|
|
203
205
|
// the answers first, then the decision that cites them (the order the layer's recorder sends)
|
|
204
206
|
if (input.answers) {
|
package/dist/chains.d.ts
CHANGED
|
@@ -13,6 +13,10 @@ export declare const jevLogsOn: (chainId: number) => {
|
|
|
13
13
|
address: string;
|
|
14
14
|
fromBlock: number;
|
|
15
15
|
};
|
|
16
|
+
earlierAnswerLogs?: readonly {
|
|
17
|
+
address: string;
|
|
18
|
+
fromBlock: number;
|
|
19
|
+
}[];
|
|
16
20
|
} | null;
|
|
17
21
|
/** Every chain that carries Jev logs, the devnet first, then Base, then the rest by id. */
|
|
18
22
|
export declare const JEV_CHAINS: readonly number[];
|
package/dist/verify.js
CHANGED
|
@@ -15,6 +15,33 @@ const hexN = (n) => '0x' + n.toString(16);
|
|
|
15
15
|
async function logs(rpc, f, address, topics, fromBlock, toBlock, chainId) {
|
|
16
16
|
return (await rpcCall(rpc, f, 'eth_getLogs', [{ address, topics, fromBlock: hexN(fromBlock), toBlock: toBlock == null ? 'latest' : hexN(toBlock) }], { chainId })) ?? [];
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* _LOGS_AT_TRUSTED_v1_: the rows of the one block JevAnswerLog.recordedAt named. That block holds a trusted record, so an
|
|
20
|
+
* empty answer is the endpoint's (one that serves only recent logs answers [] for an older block instead of an error:
|
|
21
|
+
* base.rpc.blxrbdn.com, first in Base's rotation, did for a 1.35M-block-old record on 2026-10-29) and the next endpoint
|
|
22
|
+
* is asked. [] only when every endpoint that answered said so; no answer at all is rpc_unavailable, as before.
|
|
23
|
+
*/
|
|
24
|
+
async function logsAtRecorded(rpc, f, address, topics, block, chainId) {
|
|
25
|
+
const urls = typeof rpc === 'string' ? [rpc] : rpc;
|
|
26
|
+
let answered = false;
|
|
27
|
+
let last = null;
|
|
28
|
+
for (const u of urls) {
|
|
29
|
+
try {
|
|
30
|
+
const l = await logs(u, f, address, topics, block, block, chainId);
|
|
31
|
+
answered = true;
|
|
32
|
+
if (l.length)
|
|
33
|
+
return l;
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
if (e instanceof JevChainError && e.code !== 'rpc_unavailable')
|
|
37
|
+
throw e;
|
|
38
|
+
last = e;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!answered && last)
|
|
42
|
+
throw last;
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
18
45
|
const SEL_RECORDED_AT = keccakHex('recordedAt(bytes32)').slice(0, 10);
|
|
19
46
|
/** JevAnswerLog.recordedAt(digest): the block of the first trusted record, 0 when none. */
|
|
20
47
|
async function recordedAt(rpc, f, address, digest, chainId) {
|
|
@@ -125,9 +152,14 @@ export async function verify(x, opts = {}) {
|
|
|
125
152
|
const given = typeof opts.rpc === 'string' ? opts.rpc.split(',').map((u) => u.trim()).filter(Boolean) : opts.rpc;
|
|
126
153
|
const rpc = given?.length ? given : await rpcRotation(chainId, f);
|
|
127
154
|
if (chainId !== DEVNET) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
155
|
+
// _JEV_SEATS_v1_: the answer log records go to (JevAnswerLogV2 where live), then the earlier ones still read (Base: the first log)
|
|
156
|
+
for (const log of [dev.answerLog, ...(dev.earlierAnswerLogs ?? [])]) {
|
|
157
|
+
const at = await recordedAt(rpc, f, log.address, answersDigest, chainId);
|
|
158
|
+
if (at > 0) {
|
|
159
|
+
onChain.answers = (await logsAtRecorded(rpc, f, log.address, [TOPIC_ANSWERED, null, null, answersDigest], at, chainId)).map(answerEvent);
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
131
163
|
}
|
|
132
164
|
else
|
|
133
165
|
onChain.answers = (await logs(rpc, f, dev.answerLog.address, [TOPIC_ANSWERED, null, null, answersDigest], dev.answerLog.fromBlock, undefined, chainId)).map(answerEvent);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taifoon/jev",
|
|
3
|
-
"version": "0.
|
|
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.",
|
|
3
|
+
"version": "0.4.0",
|
|
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 third-party runtime dependencies, no key inside.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jev",
|
|
7
7
|
"typesafe",
|
|
@@ -18,7 +18,16 @@
|
|
|
18
18
|
"ai-agents",
|
|
19
19
|
"on-chain",
|
|
20
20
|
"attestation",
|
|
21
|
-
"base"
|
|
21
|
+
"base",
|
|
22
|
+
"taifoon",
|
|
23
|
+
"agent-evaluation",
|
|
24
|
+
"ai-evaluation",
|
|
25
|
+
"llm-evaluation",
|
|
26
|
+
"verifiable-ai",
|
|
27
|
+
"receipt",
|
|
28
|
+
"x402",
|
|
29
|
+
"arbitrum",
|
|
30
|
+
"monad"
|
|
22
31
|
],
|
|
23
32
|
"license": "MIT",
|
|
24
33
|
"author": {
|
|
@@ -51,6 +60,7 @@
|
|
|
51
60
|
"examples",
|
|
52
61
|
"README.md",
|
|
53
62
|
"LICENSE",
|
|
63
|
+
"CHANGELOG.md",
|
|
54
64
|
"!docs/demo.gif"
|
|
55
65
|
],
|
|
56
66
|
"sideEffects": false,
|