@skill-harness/adapters 0.18.0 → 0.20.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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # @skill-harness/adapters
2
2
 
3
3
  Harness adapters for [skill-harness](https://github.com/mojomanyana/skill-harness):
4
- the `pi` runner + `claude-code` judge routing, the frozen pi-daddy 0.17/v2
4
+ the Pi subject/judge runner, the frozen pi-daddy 0.17/v2
5
5
  normalizer, and the separately pinned production ledger-v3 normalizer.
6
6
 
7
7
  Internal — use the `skill-harness` CLI. See the repo for docs.
@@ -0,0 +1,3 @@
1
+ import { type ExecutionTraceV1 } from "@skill-harness/core";
2
+ /** Apply the repository's dated token prices to one Pi execution trace. */
3
+ export declare function priceSubjectUsage(trace: ExecutionTraceV1): ExecutionTraceV1;
@@ -0,0 +1,24 @@
1
+ import { traceSha256 } from "@skill-harness/core";
2
+ import table from "../prices/model-prices.json" with { type: "json" };
3
+ const prices = table.models;
4
+ const MILLION = 1_000_000;
5
+ /** Apply the repository's dated token prices to one Pi execution trace. */
6
+ export function priceSubjectUsage(trace) {
7
+ if (!trace.metrics)
8
+ return trace;
9
+ const price = prices[trace.subject.model];
10
+ const { input_tokens, output_tokens, cache_read_tokens } = trace.metrics;
11
+ const hasUsage = input_tokens !== null || output_tokens !== null || cache_read_tokens !== null;
12
+ const cost = price && hasUsage
13
+ ? ((input_tokens ?? 0) * price.input + (cache_read_tokens ?? 0) * price.cachedInput + (output_tokens ?? 0) * price.output) / MILLION
14
+ : null;
15
+ const metrics = {
16
+ ...trace.metrics,
17
+ cost_usd: cost !== null && cost > 0 ? cost : null,
18
+ cost_source: cost !== null && cost > 0 ? "price-table" : "unreported",
19
+ price_as_of: table.asOf,
20
+ };
21
+ const priced = { ...trace, cost_usd: metrics.cost_usd, metrics };
22
+ return { ...priced, trace_sha256: traceSha256(priced) };
23
+ }
24
+ //# sourceMappingURL=model-pricing.js.map
package/dist/pi.js CHANGED
@@ -2,6 +2,7 @@ import { existsSync, mkdtempSync, readFileSync, statSync } from "node:fs";
2
2
  import { tmpdir, homedir } from "node:os";
3
3
  import { join, resolve } from "node:path";
4
4
  import { runPiJson } from "./pi-json.js";
5
+ import { priceSubjectUsage } from "./model-pricing.js";
5
6
  import { exec, onPath, envNum, traceSha256, withProviderFailure } from "@skill-harness/core";
6
7
  const PI_TIMEOUT_MS = envNum("PI_TIMEOUT_MS", 300_000);
7
8
  /**
@@ -97,6 +98,7 @@ function header(turnNo, total, text) {
97
98
  }
98
99
  export const piAdapter = {
99
100
  name: "pi",
101
+ preferStructured: true,
100
102
  available() {
101
103
  return Promise.resolve(onPath("pi"));
102
104
  },
@@ -191,9 +193,8 @@ export const piAdapter = {
191
193
  * two drifted, a trace-gated scenario would be measuring a different delivery
192
194
  * than an ungated one, and the gate would be attesting to the wrong execution.
193
195
  *
194
- * The transcript is REBUILT from each turn's final assistant message rather
195
- * than read from stdout, which is byte-identical to print mode's output (proven
196
- * on a deterministic prompt; see docs/pi-native-capture-design-2026-08-08.md §2).
196
+ * The transcript is rebuilt from each turn's final assistant message rather
197
+ * than read from stdout; fixture-backed parity tests pin the expected output.
197
198
  */
198
199
  async runStructured(req) {
199
200
  const common = [
@@ -258,9 +259,10 @@ export const piAdapter = {
258
259
  // leaves it unrecoverable from the saved transcript.
259
260
  if (providerFailure === null && r.providerFailure)
260
261
  providerFailure = r.providerFailure;
261
- traces.push(r.trace);
262
+ const pricedTrace = priceSubjectUsage(r.trace);
263
+ traces.push(pricedTrace);
262
264
  parts.push(header(i + 1, total, req.turns[i]));
263
- parts.push(`<<< ASSISTANT:\n${r.trace.final_text.trim()}\n`);
265
+ parts.push(`<<< ASSISTANT:\n${pricedTrace.final_text.trim()}\n`);
264
266
  if (r.code !== 0)
265
267
  parts.push(`[pi exited ${r.code} on turn ${i + 1}]\n${r.stderr.trim()}\n`);
266
268
  }
@@ -270,20 +272,10 @@ export const piAdapter = {
270
272
  ...(providerFailure ? { providerFailure } : {}),
271
273
  };
272
274
  },
273
- /**
274
- * Run the judge: no skills, no context files, no session, single prompt.
275
- * Judge provider `claude-code` routes to the Claude Code CLI (`claude -p`),
276
- * which authenticates via the user's Claude subscription (OAuth) instead of
277
- * a provider API key.
278
- */
275
+ /** Run the judge through Pi: no skills, context files, extensions or session. */
279
276
  async judge(req) {
280
277
  if (req.model.provider === "claude-code") {
281
- const args = ["-p", req.prompt, "--model", req.model.model];
282
- const r = await exec("claude", args, { cwd: req.cwd, timeoutMs: PI_TIMEOUT_MS });
283
- if (r.stdout.trim().length === 0 && (r.code !== 0 || r.stderr.trim())) {
284
- return `[judge error: claude exited ${r.code}] ${r.stderr.trim()}`;
285
- }
286
- return r.stdout;
278
+ throw new Error("judge provider `claude-code` was removed; configure a Pi provider such as `openai-codex`");
287
279
  }
288
280
  const args = [
289
281
  "--no-skills",
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@skill-harness/adapters",
3
- "version": "0.18.0",
4
- "description": "skill-harness harness adapters — pi runner + claude-code judge routing (internal API)",
3
+ "version": "0.20.0",
4
+ "description": "skill-harness Pi runner and judge adapter (internal API)",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "main": "./dist/index.js",
8
8
  "types": "./dist/index.d.ts",
9
9
  "exports": {
10
- ".": "./dist/index.js"
10
+ ".": "./dist/index.js",
11
+ "./prices/*.json": "./prices/*.json"
11
12
  },
12
13
  "keywords": [
13
14
  "agent-skills",
@@ -23,6 +24,7 @@
23
24
  "files": [
24
25
  "dist/**/*.js",
25
26
  "dist/**/*.d.ts",
27
+ "prices/*.json",
26
28
  "LICENSE",
27
29
  "README.md"
28
30
  ],
@@ -40,6 +42,6 @@
40
42
  "prepack": "node ../../scripts/release-pack.mjs --guard"
41
43
  },
42
44
  "dependencies": {
43
- "@skill-harness/core": "0.18.0"
45
+ "@skill-harness/core": "0.20.0"
44
46
  }
45
47
  }
@@ -0,0 +1,43 @@
1
+ {
2
+ "asOf": "2026-09-29",
3
+ "currency": "USD",
4
+ "unit": "per_million_tokens",
5
+ "models": {
6
+ "accounts/fireworks/models/deepseek-v4-flash-0731": {
7
+ "input": 0.14,
8
+ "cachedInput": 0.028,
9
+ "output": 0.28,
10
+ "source": "https://fireworks.ai/models/deepseek-ai/deepseek-v4-flash-0731"
11
+ },
12
+ "accounts/fireworks/models/deepseek-v4-pro": {
13
+ "input": 1.32,
14
+ "cachedInput": 0.044,
15
+ "output": 3.96,
16
+ "source": "https://fireworks.ai/models/deepseek-ai/deepseek-v4-pro-0813"
17
+ },
18
+ "accounts/fireworks/models/deepseek-v4-pro-0813": {
19
+ "input": 1.32,
20
+ "cachedInput": 0.044,
21
+ "output": 3.96,
22
+ "source": "https://fireworks.ai/models/deepseek-ai/deepseek-v4-pro-0813"
23
+ },
24
+ "accounts/fireworks/models/glm-5p2": {
25
+ "input": 1.4,
26
+ "cachedInput": 0.14,
27
+ "output": 4.4,
28
+ "source": "https://fireworks.ai/models/fireworks/glm-5p2"
29
+ },
30
+ "accounts/fireworks/models/glm-5p3-flash": {
31
+ "input": 0.15,
32
+ "cachedInput": 0.03,
33
+ "output": 0.5,
34
+ "source": "https://fireworks.ai/models/fireworks/glm-5p3-flash"
35
+ },
36
+ "accounts/fireworks/models/kimi-k3": {
37
+ "input": 3.0,
38
+ "cachedInput": 0.3,
39
+ "output": 15.0,
40
+ "source": "https://fireworks.ai/models/fireworks/kimi-k3"
41
+ }
42
+ }
43
+ }