@tangle-network/agent-interface 0.15.0 → 0.17.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.
@@ -43,7 +43,8 @@ export declare function snapModelToHarness(harness: HarnessType, modelId: string
43
43
  * `opencode` for everything else.
44
44
  */
45
45
  export declare function snapHarnessToModel(harness: HarnessType, modelId: string): HarnessType;
46
- /** The reasoning efforts a harness can express, independent of model — `none` up to its ceiling. */
46
+ /** The reasoning efforts a harness can express, independent of model — its explicit override set, or
47
+ * `none` up to its ceiling (default `ultracode` for router/model-driven harnesses). */
47
48
  export declare function harnessReasoningEfforts(harness: HarnessType): readonly ReasoningEffort[];
48
49
  /** What the caller knows about a model's own reasoning capability (from a model catalog). */
49
50
  export interface ModelReasoningCapability {
@@ -58,3 +59,9 @@ export interface ModelReasoningCapability {
58
59
  * lower ceiling caps the list there. Pass `model` from your catalog; omit it for the harness-only set.
59
60
  */
60
61
  export declare function reasoningEffortsFor(harness: HarnessType, model?: ModelReasoningCapability | null): readonly ReasoningEffort[];
62
+ /** Whether the harness's runner honors a per-turn MODEL override (vs. picking the model itself). */
63
+ export declare function harnessHonorsModel(harness: HarnessType): boolean;
64
+ /** Whether the harness's runner honors a reasoning-EFFORT override (vs. dropping it). */
65
+ export declare function harnessHonorsEffort(harness: HarnessType): boolean;
66
+ /** Whether the harness honors BOTH chat selectors — i.e. the model and effort pickers are live. */
67
+ export declare function harnessHonorsSelectors(harness: HarnessType): boolean;
@@ -122,22 +122,43 @@ export function snapHarnessToModel(harness, modelId) {
122
122
  }
123
123
  // ── Reasoning-effort support ──────────────────────────────────────────────────
124
124
  /**
125
- * The highest reasoning effort a harness's runtime can express (its native clamp ceiling). Grounded
126
- * in cli-bridge: codex's `model_reasoning_effort` caps at `high` (xhigh/ultracode clamp down); kimi's
127
- * `--thinking` is binary, so `high` is its "on"; claude-code carries the full range; `cli-base` has
128
- * no agent and thus no thinking; `nanoclaw`'s runner sends no thinking flag, so it expresses only
129
- * `none`. Router/model-driven harnesses default to the full range.
125
+ * The explicit reasoning-effort set a harness's runtime accepts when it ISN'T a plain `none…ceiling`
126
+ * slice — grounded in the cli-bridge adapters (NOT the canonical ladder):
127
+ * - codex: `model_reasoning_effort` accepts `minimal|low|medium|high` (xhigh/ultracode clamp down);
128
+ * it has no real `none` (the flag is just omitted), so `none` is dropped — `auto` covers "default".
129
+ * - claude-code: `--effort` accepts `low|medium|high|xhigh|max`. `ultracode` is the ladder's stand-in
130
+ * for claude's `max` (clamped at runtime); `minimal`→`low` and `none`/`auto`→no flag, so both are
131
+ * dropped as redundant.
132
+ * - pi / openclaw: `--thinking` accepts `minimal…xhigh` (max/ultracode clamp to `xhigh`; no `none`).
133
+ * - kimi-code: `--thinking` is BINARY (off/on) — `minimal` is the only value that emits
134
+ * `--no-thinking`, `high` is "thinking on". So two levels, not five.
135
+ */
136
+ const harnessReasoningEffortsOverride = {
137
+ codex: ["minimal", "low", "medium", "high"],
138
+ "claude-code": ["low", "medium", "high", "xhigh", "ultracode"],
139
+ pi: ["minimal", "low", "medium", "high", "xhigh"],
140
+ openclaw: ["minimal", "low", "medium", "high", "xhigh"],
141
+ "kimi-code": ["minimal", "high"],
142
+ };
143
+ /**
144
+ * The ceiling for harnesses whose set IS a plain `none…ceiling` slice. Only the no-thinking runners
145
+ * need an entry (`cli-base` has no agent; `nanoclaw` sends no thinking flag). Harnesses with a
146
+ * provider-clamped or non-contiguous set live in {@link harnessReasoningEffortsOverride}; router /
147
+ * model-driven harnesses (opencode, gemini, …) have no entry → default to the full ladder, narrowed
148
+ * by the model's own capability.
130
149
  */
131
150
  const harnessReasoningCeiling = {
132
151
  "cli-base": "none",
133
- codex: "high",
134
- "kimi-code": "high",
135
- "claude-code": "ultracode",
136
152
  nanoclaw: "none",
137
153
  };
138
- /** The reasoning efforts a harness can express, independent of model — `none` up to its ceiling. */
154
+ /** The reasoning efforts a harness can express, independent of model — its explicit override set, or
155
+ * `none` up to its ceiling (default `ultracode` for router/model-driven harnesses). */
139
156
  export function harnessReasoningEfforts(harness) {
140
- const ceiling = harnessReasoningCeiling[canonicalizeHarness(harness)] ?? "ultracode";
157
+ const canonical = canonicalizeHarness(harness);
158
+ const override = harnessReasoningEffortsOverride[canonical];
159
+ if (override)
160
+ return override;
161
+ const ceiling = harnessReasoningCeiling[canonical] ?? "ultracode";
141
162
  return reasoningLadder.slice(0, reasoningLadder.indexOf(ceiling) + 1);
142
163
  }
143
164
  /**
@@ -156,3 +177,41 @@ export function reasoningEffortsFor(harness, model) {
156
177
  }
157
178
  return efforts;
158
179
  }
180
+ // ── Per-turn selector support (does the harness honor the chat pickers?) ──────
181
+ /**
182
+ * Harnesses whose runner DROPS a per-turn selector — grounded in the cli-bridge adapter audit, NOT a
183
+ * guess. Most harnesses honor both selectors, so only the exceptions are listed; a harness absent from
184
+ * a set honors that selector. Keyed by the BASE runner (aliases canonicalized).
185
+ *
186
+ * - model dropped: `amp` (own agent picks the model), `openclaw` (dispatcher routes by its own
187
+ * config), `nanoclaw` (socket-bridge runner is config/env-driven).
188
+ * - effort dropped: `amp`, `factory-droids`, `hermes`, `nanoclaw`, and `acp` (no thinking flag is
189
+ * plumbed to the underlying CLI — the runner reads no `reasoningEffort`).
190
+ *
191
+ * This is distinct from {@link reasoningEffortsFor} (which levels a harness can EXPRESS): a picker uses
192
+ * these to trim or mark harnesses up front, so a user's model/effort choice is never silently ignored.
193
+ */
194
+ const harnessIgnoresModel = new Set([
195
+ "amp",
196
+ "openclaw",
197
+ "nanoclaw",
198
+ ]);
199
+ const harnessIgnoresEffort = new Set([
200
+ "amp",
201
+ "factory-droids",
202
+ "hermes",
203
+ "nanoclaw",
204
+ "acp",
205
+ ]);
206
+ /** Whether the harness's runner honors a per-turn MODEL override (vs. picking the model itself). */
207
+ export function harnessHonorsModel(harness) {
208
+ return !harnessIgnoresModel.has(canonicalizeHarness(harness));
209
+ }
210
+ /** Whether the harness's runner honors a reasoning-EFFORT override (vs. dropping it). */
211
+ export function harnessHonorsEffort(harness) {
212
+ return !harnessIgnoresEffort.has(canonicalizeHarness(harness));
213
+ }
214
+ /** Whether the harness honors BOTH chat selectors — i.e. the model and effort pickers are live. */
215
+ export function harnessHonorsSelectors(harness) {
216
+ return harnessHonorsModel(harness) && harnessHonorsEffort(harness);
217
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-interface",
3
- "version": "0.15.0",
3
+ "version": "0.17.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",