@claudexor/core 3.1.0 → 3.1.1

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/dist/effort.d.ts CHANGED
@@ -1,18 +1,60 @@
1
1
  import type { EffortHint } from "@claudexor/schema";
2
2
  /**
3
- * Map a requested reasoning-effort hint onto the nearest level a harness
4
- * actually supports.
3
+ * Effort resolution against VENDOR-ordered ladders. There is no static rank
4
+ * table anywhere in this repo: a level's rank is its position in the ladder the
5
+ * vendor itself advertised (a model's own ordered list, or the harness's merged
6
+ * ladder — `mergeEffortLadders` in the schema package). Ranking is NOT
7
+ * permission: what a run may actually use is whatever the resolved (harness,
8
+ * model) ADVERTISES, so a level newer than this repo passes through untouched
9
+ * the moment the vendor ships it.
10
+ */
11
+ /**
12
+ * Outcome of resolving a requested effort against an advertised vocabulary.
13
+ * `rejected` carries actionable text naming what IS advertised — an unknown
14
+ * level is never silently downgraded into something we merely guessed at.
15
+ */
16
+ export type EffortCheck = {
17
+ status: "ok";
18
+ effort: EffortHint | null;
19
+ clamped: boolean;
20
+ } | {
21
+ status: "rejected";
22
+ message: string;
23
+ };
24
+ /**
25
+ * Resolve a requested reasoning-effort level against the levels a specific
26
+ * (harness, model) advertises. THE single owner of effort semantics; every
27
+ * surface (adapters, settings writes, preflight) resolves through it.
5
28
  *
6
- * - `requested` null/undefined null (no effort was asked for; pass no flag).
7
- * - `supported` empty null (effort is NOT a tunable surface for this adapter;
8
- * it passes no effort flag at all honest, not a silent clamp to a default).
9
- * - `requested` exactly supported returned unchanged.
10
- * - otherwise CLAMP to the nearest supported level BY RANK: above the strongest
11
- * supported the strongest; below the weakest the weakest; in-between the
12
- * closest by rank, ties resolving to the LOWER (cheaper) level.
29
+ * `advertised` is what the resolved target accepts (the model's own ordered
30
+ * list, or the harness ladder when the model recorded none). `ladder` is the
31
+ * rank authority for clamping: the harness's MERGED vendor order, so a level
32
+ * one sibling model advertises can clamp onto what THIS model accepts (`ultra`
33
+ * on gpt-5.4 `xhigh`, because the merged codex ladder places `ultra` above
34
+ * it). It defaults to `advertised` itself the degenerate case where nothing
35
+ * beyond the target's own order is known, including a harness whose models'
36
+ * orders CONTRADICT each other: pass `advertised` there, which makes
37
+ * cross-model clamping impossible by construction and refuses instead of
38
+ * inventing an order.
13
39
  *
14
- * Pure and data-driven: the adapter feeds its own declared `effort_levels` and
15
- * never hard-codes a clamp table.
40
+ * - nothing requested ok, no effort (pass no flag).
41
+ * - `advertised` empty → ok, no effort: effort is not a tunable surface here, so
42
+ * the caller discloses it as ignored (INV-105) instead of clamping to a guess.
43
+ * - requested IS advertised → PASS THROUGH VERBATIM. This is what makes a
44
+ * future vendor level work with no Claudexor change.
45
+ * - requested is not advertised but the LADDER places it → CLAMP to the nearest
46
+ * advertised level by ladder position (ties resolve to the cheaper one).
47
+ * - requested is unknown to the ladder too → REJECT, naming the advertised
48
+ * set. We cannot place it, so any "nearest" would be invented.
49
+ */
50
+ export declare function resolveEffort(requested: EffortHint | null | undefined, advertised: readonly EffortHint[], ladder?: readonly EffortHint[]): EffortCheck;
51
+ /**
52
+ * Map a requested effort onto a level the resolved (harness, model) accepts, or
53
+ * null when none should be sent. Thin translational wrapper over `resolveEffort`
54
+ * for arg builders, which must never emit a level the vendor would reject: a
55
+ * rejection yields null (send NO flag, keep the vendor default) rather than a
56
+ * fabricated downgrade. Surfaces that can talk back to the user call
57
+ * `resolveEffort` and report its `message`.
16
58
  */
17
- export declare function normalizeEffort(requested: EffortHint | null | undefined, supported: readonly EffortHint[]): EffortHint | null;
59
+ export declare function normalizeEffort(requested: EffortHint | null | undefined, advertised: readonly EffortHint[], ladder?: readonly EffortHint[]): EffortHint | null;
18
60
  //# sourceMappingURL=effort.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"effort.d.ts","sourceRoot":"","sources":["../src/effort.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAiBpD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EACxC,SAAS,EAAE,SAAS,UAAU,EAAE,GAC/B,UAAU,GAAG,IAAI,CAoBnB"}
1
+ {"version":3,"file":"effort.d.ts","sourceRoot":"","sources":["../src/effort.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;;;;;;;GAQG;AAEH;;;;GAIG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAC7D;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EACxC,UAAU,EAAE,SAAS,UAAU,EAAE,EACjC,MAAM,GAAE,SAAS,UAAU,EAAe,GACzC,WAAW,CAkCb;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EACxC,UAAU,EAAE,SAAS,UAAU,EAAE,EACjC,MAAM,GAAE,SAAS,UAAU,EAAe,GACzC,UAAU,GAAG,IAAI,CAGnB"}
package/dist/effort.js CHANGED
@@ -1,50 +1,71 @@
1
- import { EffortHint as EffortHintSchema } from "@claudexor/schema";
2
1
  /**
3
- * The full cross-harness reasoning-effort ladder, ordered weakest→strongest.
4
- * DERIVED from the EffortHint enum's declaration order (the single source) so the
5
- * ladder can never drift from the enum: a future level (e.g. `ultra`) appended to
6
- * the enum is automatically ranked and every adapter clamps it with no code
7
- * change. An EffortHint's RANK is its index here; the normalizer below clamps any
8
- * requested level onto the nearest level a given adapter actually supports.
9
- */
10
- const EFFORT_LADDER = EffortHintSchema.options;
11
- function rank(level) {
12
- return EFFORT_LADDER.indexOf(level);
13
- }
14
- /**
15
- * Map a requested reasoning-effort hint onto the nearest level a harness
16
- * actually supports.
2
+ * Resolve a requested reasoning-effort level against the levels a specific
3
+ * (harness, model) advertises. THE single owner of effort semantics; every
4
+ * surface (adapters, settings writes, preflight) resolves through it.
17
5
  *
18
- * - `requested` null/undefined null (no effort was asked for; pass no flag).
19
- * - `supported` empty null (effort is NOT a tunable surface for this adapter;
20
- * it passes no effort flag at all honest, not a silent clamp to a default).
21
- * - `requested` exactly supported returned unchanged.
22
- * - otherwise CLAMP to the nearest supported level BY RANK: above the strongest
23
- * supported the strongest; below the weakest the weakest; in-between the
24
- * closest by rank, ties resolving to the LOWER (cheaper) level.
6
+ * `advertised` is what the resolved target accepts (the model's own ordered
7
+ * list, or the harness ladder when the model recorded none). `ladder` is the
8
+ * rank authority for clamping: the harness's MERGED vendor order, so a level
9
+ * one sibling model advertises can clamp onto what THIS model accepts (`ultra`
10
+ * on gpt-5.4 `xhigh`, because the merged codex ladder places `ultra` above
11
+ * it). It defaults to `advertised` itself the degenerate case where nothing
12
+ * beyond the target's own order is known, including a harness whose models'
13
+ * orders CONTRADICT each other: pass `advertised` there, which makes
14
+ * cross-model clamping impossible by construction and refuses instead of
15
+ * inventing an order.
25
16
  *
26
- * Pure and data-driven: the adapter feeds its own declared `effort_levels` and
27
- * never hard-codes a clamp table.
17
+ * - nothing requested ok, no effort (pass no flag).
18
+ * - `advertised` empty → ok, no effort: effort is not a tunable surface here, so
19
+ * the caller discloses it as ignored (INV-105) instead of clamping to a guess.
20
+ * - requested IS advertised → PASS THROUGH VERBATIM. This is what makes a
21
+ * future vendor level work with no Claudexor change.
22
+ * - requested is not advertised but the LADDER places it → CLAMP to the nearest
23
+ * advertised level by ladder position (ties resolve to the cheaper one).
24
+ * - requested is unknown to the ladder too → REJECT, naming the advertised
25
+ * set. We cannot place it, so any "nearest" would be invented.
28
26
  */
29
- export function normalizeEffort(requested, supported) {
30
- if (requested === null || requested === undefined)
31
- return null;
32
- if (supported.length === 0)
33
- return null;
34
- if (supported.includes(requested))
35
- return requested;
36
- const want = rank(requested);
37
- let best = null;
38
- let bestDistance = Number.POSITIVE_INFINITY;
39
- for (const level of supported) {
40
- const distance = Math.abs(rank(level) - want);
41
- // Strictly-closer wins; on a tie keep the LOWER-ranked (cheaper) candidate.
27
+ export function resolveEffort(requested, advertised, ladder = advertised) {
28
+ if (requested === null || requested === undefined) {
29
+ return { status: "ok", effort: null, clamped: false };
30
+ }
31
+ if (advertised.length === 0)
32
+ return { status: "ok", effort: null, clamped: false };
33
+ if (advertised.includes(requested))
34
+ return { status: "ok", effort: requested, clamped: false };
35
+ const want = ladder.indexOf(requested);
36
+ // Only levels the ladder places can host a clamp; a level outside the ladder
37
+ // is a valid TARGET only through the exact-match branch above.
38
+ const rankable = advertised.filter((level) => ladder.indexOf(level) >= 0);
39
+ if (want < 0 || rankable.length === 0) {
40
+ return {
41
+ status: "rejected",
42
+ message: `effort "${requested}" is not advertised here and the advertised ladder cannot place it ` +
43
+ `(advertised: ${advertised.join(", ")})`,
44
+ };
45
+ }
46
+ let best = rankable[0];
47
+ let bestDistance = Math.abs(ladder.indexOf(best) - want);
48
+ for (const level of rankable.slice(1)) {
49
+ const distance = Math.abs(ladder.indexOf(level) - want);
50
+ // Strictly-closer wins; on a tie keep the LOWER-positioned (cheaper) candidate.
42
51
  if (distance < bestDistance ||
43
- (distance === bestDistance && best !== null && rank(level) < rank(best))) {
52
+ (distance === bestDistance && ladder.indexOf(level) < ladder.indexOf(best))) {
44
53
  best = level;
45
54
  bestDistance = distance;
46
55
  }
47
56
  }
48
- return best;
57
+ return { status: "ok", effort: best, clamped: true };
58
+ }
59
+ /**
60
+ * Map a requested effort onto a level the resolved (harness, model) accepts, or
61
+ * null when none should be sent. Thin translational wrapper over `resolveEffort`
62
+ * for arg builders, which must never emit a level the vendor would reject: a
63
+ * rejection yields null (send NO flag, keep the vendor default) rather than a
64
+ * fabricated downgrade. Surfaces that can talk back to the user call
65
+ * `resolveEffort` and report its `message`.
66
+ */
67
+ export function normalizeEffort(requested, advertised, ladder = advertised) {
68
+ const check = resolveEffort(requested, advertised, ladder);
69
+ return check.status === "ok" ? check.effort : null;
49
70
  }
50
71
  //# sourceMappingURL=effort.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"effort.js","sourceRoot":"","sources":["../src/effort.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,IAAI,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEnE;;;;;;;GAOG;AACH,MAAM,aAAa,GAA0B,gBAAgB,CAAC,OAAO,CAAC;AAEtE,SAAS,IAAI,CAAC,KAAiB;IAC7B,OAAO,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe,CAC7B,SAAwC,EACxC,SAAgC;IAEhC,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC/D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAEpD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7B,IAAI,IAAI,GAAsB,IAAI,CAAC;IACnC,IAAI,YAAY,GAAG,MAAM,CAAC,iBAAiB,CAAC;IAC5C,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;QAC9C,4EAA4E;QAC5E,IACE,QAAQ,GAAG,YAAY;YACvB,CAAC,QAAQ,KAAK,YAAY,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EACxE,CAAC;YACD,IAAI,GAAG,KAAK,CAAC;YACb,YAAY,GAAG,QAAQ,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"effort.js","sourceRoot":"","sources":["../src/effort.ts"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,aAAa,CAC3B,SAAwC,EACxC,UAAiC,EACjC,SAAgC,UAAU;IAE1C,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAClD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACxD,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACnF,IAAI,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAE/F,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACvC,6EAA6E;IAC7E,+DAA+D;IAC/D,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1E,IAAI,IAAI,GAAG,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtC,OAAO;YACL,MAAM,EAAE,UAAU;YAClB,OAAO,EACL,WAAW,SAAS,qEAAqE;gBACzF,gBAAgB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;SAC3C,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,GAAe,QAAQ,CAAC,CAAC,CAAe,CAAC;IACjD,IAAI,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IACzD,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;QACxD,gFAAgF;QAChF,IACE,QAAQ,GAAG,YAAY;YACvB,CAAC,QAAQ,KAAK,YAAY,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAC3E,CAAC;YACD,IAAI,GAAG,KAAK,CAAC;YACb,YAAY,GAAG,QAAQ,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACvD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,SAAwC,EACxC,UAAiC,EACjC,SAAgC,UAAU;IAE1C,MAAM,KAAK,GAAG,aAAa,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;IAC3D,OAAO,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACrD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claudexor/core",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "license": "MIT",
5
5
  "description": "HarnessAdapter contract, process helpers, typed errors, and low-level execution utilities.",
6
6
  "type": "module",
@@ -20,8 +20,8 @@
20
20
  ],
21
21
  "dependencies": {
22
22
  "@playwright/mcp": "0.0.78",
23
- "@claudexor/schema": "3.1.0",
24
- "@claudexor/util": "3.1.0"
23
+ "@claudexor/util": "3.1.1",
24
+ "@claudexor/schema": "3.1.1"
25
25
  },
26
26
  "repository": {
27
27
  "type": "git",