@taifoon/jev 0.2.8 → 0.2.9
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/README.md +1 -0
- package/bin/run.mjs +5 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/pipeline.d.ts +11 -0
- package/dist/pipeline.js +21 -2
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -118,6 +118,7 @@ Safe by default: your own TypeSafe key only, nothing recorded, nothing signed or
|
|
|
118
118
|
| `--layer <https url>` / `--no-layer` | `https://coord.taifoon.dev` | Where jobs and quotes are read |
|
|
119
119
|
| `--protocol <name>` | from the job id | Evaluator seat: `virtuals-erc8183`, `virtuals-memo-acp`, `bitagent-erc8183`, `assurance-hook`, `judge-adapter` |
|
|
120
120
|
| `--price-usdc <n>` | the job's budget | Price for the premium quote |
|
|
121
|
+
| `--seller-record <k>/<n>` | read from the layer | Price the premium here from the seller's record (k delivered of n graded) with [`@taifoon/jev-wilson`](https://www.npmjs.com/package/@taifoon/jev-wilson): the layer's numbers, no request |
|
|
121
122
|
| `--yes` / `--json` | ask per step / text | Run every step without asking / print the whole trace as JSON |
|
|
122
123
|
|
|
123
124
|
Environment: `TYPESAFE_KEY` (your key; without it a job that needs Jev stops and says where to get one, while a job the
|
package/bin/run.mjs
CHANGED
|
@@ -35,7 +35,7 @@ function factOf(r) {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const USAGE = 'jev run [--demo | --job <chain>:<id> | --job-file job.json | --evidence pack.json] [--answers answers.json] [--record none|devnet|base|both] [--layer <https url> | --no-layer] [--protocol <name>] [--price-usdc <n>] [--yes] [--json]';
|
|
38
|
+
const USAGE = 'jev run [--demo | --job <chain>:<id> | --job-file job.json | --evidence pack.json] [--answers answers.json] [--record none|devnet|base|both] [--layer <https url> | --no-layer] [--protocol <name>] [--price-usdc <n>] [--seller-record <k>/<n>] [--yes] [--json]';
|
|
39
39
|
const PROTOCOLS = ['assurance-hook', 'judge-adapter', 'virtuals-erc8183', 'virtuals-memo-acp', 'bitagent-erc8183'];
|
|
40
40
|
/** A stranger's typo must never run something else: every flag is known, every value checked, exit 2 with the fix. */
|
|
41
41
|
function refuse(msg) { process.stderr.write(`jev run: ${msg}\n ${USAGE}\n`); process.exit(2); }
|
|
@@ -56,7 +56,7 @@ export async function run(argv) {
|
|
|
56
56
|
const ansFile = file('--answers');
|
|
57
57
|
const rec = demo ? JSON.parse(readFileSync(new URL('../examples/jobs/base-bitagent-7287.recorded.json', import.meta.url), 'utf8')) : null;
|
|
58
58
|
const network = val('--record') ?? val('--network') ?? 'none'; const layer = noLayer ? false : val('--layer');
|
|
59
|
-
const protocol = val('--protocol'); const price = val('--price-usdc');
|
|
59
|
+
const protocol = val('--protocol'); const price = val('--price-usdc'); const sellerRec = val('--seller-record');
|
|
60
60
|
if (a.length) refuse(`unknown flag ${a[0]}`);
|
|
61
61
|
if (!['none', 'devnet', 'base', 'both'].includes(network)) refuse(`--record is none, devnet, base or both (got ${network})`);
|
|
62
62
|
if (demo && (job || evFile || jobFile || ansFile)) refuse('--demo replays one recorded job: drop --job, --job-file, --evidence and --answers');
|
|
@@ -65,6 +65,8 @@ export async function run(argv) {
|
|
|
65
65
|
if (layer && !/^https:\/\//.test(layer)) refuse('--layer must be an https:// URL');
|
|
66
66
|
if (protocol && !PROTOCOLS.includes(protocol)) refuse(`--protocol is one of ${PROTOCOLS.join(', ')}`);
|
|
67
67
|
if (price !== undefined && !(Number(price) > 0)) refuse(`--price-usdc must be a positive number (got ${price})`);
|
|
68
|
+
const recM = sellerRec === undefined ? null : /^(\d+)\/(\d+)$/.exec(sellerRec);
|
|
69
|
+
if (sellerRec !== undefined && (!recM || Number(recM[1]) > Number(recM[2]) || Number(recM[2]) === 0)) refuse(`--seller-record must be <delivered>/<graded>, e.g. 60/62 (got ${sellerRec})`);
|
|
68
70
|
const { pipeline, STEPS, prepareJob } = await import('../dist/index.js');
|
|
69
71
|
|
|
70
72
|
const t = createTerm({ quiet: json });
|
|
@@ -72,7 +74,7 @@ export async function run(argv) {
|
|
|
72
74
|
t.info(`jev run · ${noLayer ? 'offline' : `layer ${layer ?? 'https://coord.taifoon.dev'}`} · grade on ${demo ? `Jev's recorded answers for ${rec.job.ref} (${rec.job.task})` : ansFile ? 'supplied answers' : process.env.TYPESAFE_KEY ? 'your TypeSafe key' : 'no key: set TYPESAFE_KEY, or try --demo'} · record → ${network === 'none' ? 'none (opt in with --record devnet|base|both)' : network}${process.env.TAIFOON_RELAYER_KEY ? ' + the layer' : ''}`);
|
|
73
75
|
|
|
74
76
|
const trace = await pipeline({
|
|
75
|
-
layer, job, network, protocol, priceUsdc: price ? Number(price) : undefined,
|
|
77
|
+
layer, job, network, protocol, priceUsdc: price ? Number(price) : undefined, sellerRecord: recM ? { k: Number(recM[1]), n: Number(recM[2]) } : undefined,
|
|
76
78
|
evidence: rec ? { subject: rec.subject.ref, from: `the recorded job ${rec.job.ref} (${rec.job.protocol}, ${rec.job.price})`, chainId: rec.subject.chainId, label: rec.subject.label, state: rec.evidence, delivered: rec.facts.delivered, checks: rec.facts.checks } : jobFile ? prepareJob(JSON.parse(readFileSync(jobFile, 'utf8'))).pack : evFile ? JSON.parse(readFileSync(evFile, 'utf8')) : undefined,
|
|
77
79
|
answers: rec ? rec.answers : ansFile ? JSON.parse(readFileSync(ansFile, 'utf8')) : undefined, ...(rec ? { model: rec.model } : {}),
|
|
78
80
|
key: process.env.TYPESAFE_KEY || null, relayerKey: process.env.TAIFOON_RELAYER_KEY || null,
|
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export { prepareJob, runCheck } from './job.js';
|
|
|
19
19
|
export { record } from './record.js';
|
|
20
20
|
export { evaluatorCall } from './evaluator/index.js';
|
|
21
21
|
export { verify } from './verify.js';
|
|
22
|
-
export { pipeline, STEPS, LAYER, factsFromEvidence, protocolFor, parseJob } from './pipeline.js';
|
|
22
|
+
export { pipeline, STEPS, LAYER, factsFromEvidence, protocolFor, parseJob, localQuote } from './pipeline.js';
|
|
23
23
|
export { RUBRIC_v1 } from './rubric.js';
|
|
24
24
|
export { CONTRACTS } from './contracts.js';
|
|
25
25
|
export type { GradeInput, Receipt } from './grade.js';
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,6 @@ export { prepareJob, runCheck } from './job.js';
|
|
|
19
19
|
export { record } from './record.js';
|
|
20
20
|
export { evaluatorCall } from './evaluator/index.js';
|
|
21
21
|
export { verify } from './verify.js';
|
|
22
|
-
export { pipeline, STEPS, LAYER, factsFromEvidence, protocolFor, parseJob } from './pipeline.js';
|
|
22
|
+
export { pipeline, STEPS, LAYER, factsFromEvidence, protocolFor, parseJob, localQuote } from './pipeline.js';
|
|
23
23
|
export { RUBRIC_v1 } from './rubric.js';
|
|
24
24
|
export { CONTRACTS } from './contracts.js';
|
package/dist/pipeline.d.ts
CHANGED
|
@@ -127,12 +127,23 @@ export type PipelineOpts = {
|
|
|
127
127
|
chainVerify?: boolean;
|
|
128
128
|
/** price for the premium step, in USDC; default: the job's budget */
|
|
129
129
|
priceUsdc?: number | null;
|
|
130
|
+
/** the seller's record, k delivered of n graded: the premium is priced locally (@taifoon/jev-wilson, the layer's own
|
|
131
|
+
* numbers to the last digit) and the layer is not asked */
|
|
132
|
+
sellerRecord?: {
|
|
133
|
+
k: number;
|
|
134
|
+
n: number;
|
|
135
|
+
} | null;
|
|
130
136
|
/** a gate before each step: return false to skip it. The interactive CLI asks here. */
|
|
131
137
|
before?: (step: (typeof STEPS)[number], trace: Trace) => boolean | Promise<boolean>;
|
|
132
138
|
/** called after each step with its result */
|
|
133
139
|
after?: (result: StepResult, trace: Trace) => void | Promise<void>;
|
|
134
140
|
fetch?: typeof fetch;
|
|
135
141
|
};
|
|
142
|
+
/** The premium the layer would quote for this record, computed here: same z, same bound, same rounding. */
|
|
143
|
+
export declare function localQuote(record: {
|
|
144
|
+
k: number;
|
|
145
|
+
n: number;
|
|
146
|
+
}, priceUsdc: number | null): Quote;
|
|
136
147
|
/** A job reference: `8453:81100`, `8453:bitagent:8453:7287`, or a bare id (chain 8453). */
|
|
137
148
|
export declare function parseJob(j: string | {
|
|
138
149
|
chainId: number;
|
package/dist/pipeline.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// pipeline(): one job through the coordination layer's steps, each step a function with a typed output.
|
|
2
2
|
// pick → evidence → facts → grade → record → evaluator → premium → verify
|
|
3
3
|
// Every step works without the layer too: pass `evidence` (your own pack) and the layer is never read; `grade` then
|
|
4
|
-
// runs on your own TypeSafe key (or answers you already have), `record` returns unsigned calls, `premium` is skipped. With the layer
|
|
4
|
+
// runs on your own TypeSafe key (or answers you already have), `record` returns unsigned calls, `premium` is priced from a `sellerRecord` you pass (or skipped). With the layer
|
|
5
5
|
// (https://coord.taifoon.dev by default) the job comes from /v1/judge/queue, the pack from /v1/judge/evidence, the
|
|
6
6
|
// seller's terms from /v1/pools/quote, and — only with a relayer key — the answers are recorded on the layer through
|
|
7
7
|
// /v1/judge/answers/record. Nothing here signs a transaction.
|
|
8
|
+
import { premium as wilsonPremium, wilson } from '@taifoon/jev-wilson';
|
|
8
9
|
import { facts as runFacts } from './facts.js';
|
|
9
10
|
import { grade } from './grade.js';
|
|
10
11
|
import { record } from './record.js';
|
|
@@ -23,6 +24,19 @@ export const STEPS = Object.freeze([
|
|
|
23
24
|
{ id: 'premium', title: 'Price the next premium from the seller record (Wilson)', route: 'POST /v1/pools/quote' },
|
|
24
25
|
{ id: 'verify', title: 'Re-derive the receipt (and find it on chain)', route: null },
|
|
25
26
|
]);
|
|
27
|
+
/** The premium the layer would quote for this record, computed here: same z, same bound, same rounding. */
|
|
28
|
+
export function localQuote(record, priceUsdc) {
|
|
29
|
+
const units = priceUsdc ? Math.round(priceUsdc * 1e6) : undefined;
|
|
30
|
+
const p = wilsonPremium(record, units === undefined ? {} : { price: units });
|
|
31
|
+
const [lo, hi] = wilson(record.n - record.k, record.n);
|
|
32
|
+
const pct = (x) => `${(x * 100).toFixed(1)}%`;
|
|
33
|
+
return {
|
|
34
|
+
guaranteed: p.covered, premium: p.amount === null ? null : p.amount.toString(), premium_ratio: p.ratio, deposit: null,
|
|
35
|
+
premium_label: p.insurable ? `${pct(lo)}–${pct(hi)} · ${record.k} of ${record.n} delivered` : 'UNKNOWN: no delivered job on record',
|
|
36
|
+
record: { n: record.n, settled: record.n, incorrect: record.n - record.k, wilson: [lo, hi], calibrated: false, insurable: p.insurable },
|
|
37
|
+
why: p.insurable ? (p.covered ? [] : [`ratio ${p.ratio.toFixed(4)} is above the 0.30 the pool covers`]) : ['a record with no delivered job is not insurable'],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
26
40
|
const num = (s) => { const m = /([0-9]+(?:\.[0-9]+)?)/.exec(s ?? ''); return m ? Number(m[1]) : null; };
|
|
27
41
|
const fact = (ev, label) => ev.facts.find(([k]) => label.test(k))?.[1];
|
|
28
42
|
/** A job reference: `8453:81100`, `8453:bitagent:8453:7287`, or a bare id (chain 8453). */
|
|
@@ -181,8 +195,13 @@ export async function pipeline(o = {}) {
|
|
|
181
195
|
});
|
|
182
196
|
await step('premium', async () => {
|
|
183
197
|
const seller = t.job.seller;
|
|
198
|
+
if (o.sellerRecord) {
|
|
199
|
+
const price = o.priceUsdc ?? budget;
|
|
200
|
+
t.quote = localQuote(o.sellerRecord, price);
|
|
201
|
+
return { source: 'local: Wilson on the record you passed', guaranteed: t.quote.guaranteed, premium_ratio: t.quote.premium_ratio, premium_label: t.quote.premium_label, record: t.quote.record ?? null };
|
|
202
|
+
}
|
|
184
203
|
if (!layer)
|
|
185
|
-
return { skip: 'offline:
|
|
204
|
+
return { skip: 'offline: pass sellerRecord (--seller-record k/n) to price locally, or a layer to read the seller\'s record' };
|
|
186
205
|
if (!seller)
|
|
187
206
|
return { skip: 'no seller address in the evidence' };
|
|
188
207
|
const price = o.priceUsdc ?? budget;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taifoon/jev",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
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",
|
|
@@ -78,5 +78,8 @@
|
|
|
78
78
|
"bin": {
|
|
79
79
|
"jev": "bin/jev.mjs",
|
|
80
80
|
"taifoon-jev": "bin/jev.mjs"
|
|
81
|
+
},
|
|
82
|
+
"dependencies": {
|
|
83
|
+
"@taifoon/jev-wilson": "^0.1.0"
|
|
81
84
|
}
|
|
82
85
|
}
|