@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 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';
@@ -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: the premium quote reads the seller\'s record from the layer' };
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.8",
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
  }