@tangle-network/agent-interface 0.17.0 → 0.18.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.
@@ -92,7 +92,8 @@ export interface AgentProfileResources {
92
92
  * - `minimal` — thinking ON, the lowest budget (distinct from `none`)
93
93
  * - `low` / `medium` / `high` / `xhigh`
94
94
  * - `ultracode` — maximum (claude-code's "ultracode" run mode; codex's `max` reconciles here).
95
- * A backend without a matching native tier clamps to its nearest (e.g. codex maps `xhigh`/`ultracode` → `high`).
95
+ * A backend without a matching native tier clamps to its nearest (e.g. codex maps `ultracode` → `xhigh`
96
+ * on models that support it).
96
97
  */
97
98
  export type ReasoningEffort = "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "ultracode";
98
99
  /**
@@ -11,9 +11,10 @@ import { type HarnessType } from "./harness.js";
11
11
  * cli-bridge backends, the sandbox UI pickers, and the router all read one truth instead of each
12
12
  * hand-rolling a divergent copy.
13
13
  *
14
- * Grounded in cli-bridge's real backend clamps (codex caps at `high`, kimi is binary on/off, claude
15
- * carries the full range, cli-base has no agent) — NOT a guessed matrix. The per-MODEL reasoning
16
- * capability (does this specific model reason at all) is dynamic catalog data the caller supplies.
14
+ * Grounded in cli-bridge's real backend clamps (codex is `low..xhigh` for current models, kimi is
15
+ * binary on/off, claude carries the full range, cli-base has no agent) — NOT a guessed matrix. The
16
+ * per-MODEL reasoning capability (does this specific model reason at all) is dynamic catalog data the
17
+ * caller supplies.
17
18
  */
18
19
  /** low → high. `none` = thinking off; `ultracode` = max (claude-code mode). */
19
20
  export declare const reasoningLadder: readonly ReasoningEffort[];
@@ -10,9 +10,10 @@ import { canonicalizeHarness } from "./harness.js";
10
10
  * cli-bridge backends, the sandbox UI pickers, and the router all read one truth instead of each
11
11
  * hand-rolling a divergent copy.
12
12
  *
13
- * Grounded in cli-bridge's real backend clamps (codex caps at `high`, kimi is binary on/off, claude
14
- * carries the full range, cli-base has no agent) — NOT a guessed matrix. The per-MODEL reasoning
15
- * capability (does this specific model reason at all) is dynamic catalog data the caller supplies.
13
+ * Grounded in cli-bridge's real backend clamps (codex is `low..xhigh` for current models, kimi is
14
+ * binary on/off, claude carries the full range, cli-base has no agent) — NOT a guessed matrix. The
15
+ * per-MODEL reasoning capability (does this specific model reason at all) is dynamic catalog data the
16
+ * caller supplies.
16
17
  */
17
18
  /** low → high. `none` = thinking off; `ultracode` = max (claude-code mode). */
18
19
  export const reasoningLadder = [
@@ -124,8 +125,8 @@ export function snapHarnessToModel(harness, modelId) {
124
125
  /**
125
126
  * The explicit reasoning-effort set a harness's runtime accepts when it ISN'T a plain `none…ceiling`
126
127
  * 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".
128
+ * - codex: current models advertise `low|medium|high|xhigh`; `none` is omitted (use `auto`) and
129
+ * legacy `minimal` requests clamp up to `low`.
129
130
  * - claude-code: `--effort` accepts `low|medium|high|xhigh|max`. `ultracode` is the ladder's stand-in
130
131
  * for claude's `max` (clamped at runtime); `minimal`→`low` and `none`/`auto`→no flag, so both are
131
132
  * dropped as redundant.
@@ -134,7 +135,7 @@ export function snapHarnessToModel(harness, modelId) {
134
135
  * `--no-thinking`, `high` is "thinking on". So two levels, not five.
135
136
  */
136
137
  const harnessReasoningEffortsOverride = {
137
- codex: ["minimal", "low", "medium", "high"],
138
+ codex: ["low", "medium", "high", "xhigh"],
138
139
  "claude-code": ["low", "medium", "high", "xhigh", "ultracode"],
139
140
  pi: ["minimal", "low", "medium", "high", "xhigh"],
140
141
  openclaw: ["minimal", "low", "medium", "high", "xhigh"],
@@ -49,6 +49,7 @@ export declare const InteractionFieldSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
49
49
  description: z.ZodOptional<z.ZodString>;
50
50
  }, z.core.$strip>>;
51
51
  multi: z.ZodOptional<z.ZodBoolean>;
52
+ allowCustom: z.ZodOptional<z.ZodBoolean>;
52
53
  default: z.ZodOptional<z.ZodArray<z.ZodString>>;
53
54
  name: z.ZodString;
54
55
  label: z.ZodString;
@@ -92,6 +93,7 @@ export declare const InteractionAnswerSpecSchema: z.ZodObject<{
92
93
  description: z.ZodOptional<z.ZodString>;
93
94
  }, z.core.$strip>>;
94
95
  multi: z.ZodOptional<z.ZodBoolean>;
96
+ allowCustom: z.ZodOptional<z.ZodBoolean>;
95
97
  default: z.ZodOptional<z.ZodArray<z.ZodString>>;
96
98
  name: z.ZodString;
97
99
  label: z.ZodString;
@@ -190,6 +192,7 @@ export declare const InteractionRequestSchema: z.ZodObject<{
190
192
  description: z.ZodOptional<z.ZodString>;
191
193
  }, z.core.$strip>>;
192
194
  multi: z.ZodOptional<z.ZodBoolean>;
195
+ allowCustom: z.ZodOptional<z.ZodBoolean>;
193
196
  default: z.ZodOptional<z.ZodArray<z.ZodString>>;
194
197
  name: z.ZodString;
195
198
  label: z.ZodString;
@@ -261,6 +264,8 @@ export type LegacyQuestion = {
261
264
  description?: string;
262
265
  }>;
263
266
  multiSelect?: boolean;
267
+ /** When true the select field accepts write-in answers beyond `options`. */
268
+ allowCustom?: boolean;
264
269
  };
265
270
  /**
266
271
  * Build an answer spec from the legacy `question` event shape. Each question
@@ -62,6 +62,12 @@ export const InteractionFieldSchema = z.discriminatedUnion("type", [
62
62
  .min(1),
63
63
  /** When true the user may pick more than one option. */
64
64
  multi: z.boolean().optional(),
65
+ /**
66
+ * When true the answer may contain write-in values outside `options`
67
+ * (e.g. a rendered "Other…" choice carrying the user's own text).
68
+ * Write-ins must still be non-empty strings.
69
+ */
70
+ allowCustom: z.boolean().optional(),
65
71
  default: z.array(z.string()).optional(),
66
72
  }),
67
73
  /** Like `text` but the value is sensitive (token/key) and must be masked. */
@@ -185,6 +191,7 @@ export function questionAnswerSpec(questions) {
185
191
  label: q.question,
186
192
  required: true,
187
193
  multi: q.multiSelect === true,
194
+ ...(q.allowCustom === true ? { allowCustom: true } : {}),
188
195
  options: q.options.map((o) => ({ value: o.label, label: o.label, description: o.description })),
189
196
  };
190
197
  }
@@ -239,8 +246,16 @@ export function validateInteractionAnswer(spec, data) {
239
246
  errors.push(`field "${field.name}" requires a selection`);
240
247
  const allowed = new Set(field.options.map((o) => o.value));
241
248
  for (const choice of v) {
242
- if (!allowed.has(choice))
243
- errors.push(`field "${field.name}" has invalid option "${choice}"`);
249
+ if (allowed.has(choice))
250
+ continue;
251
+ if (field.allowCustom === true) {
252
+ // Write-ins are open but stay fail-closed on shape: string, non-blank.
253
+ if (typeof choice !== "string" || choice.trim() === "") {
254
+ errors.push(`field "${field.name}" has blank write-in value`);
255
+ }
256
+ continue;
257
+ }
258
+ errors.push(`field "${field.name}" has invalid option "${choice}"`);
244
259
  }
245
260
  break;
246
261
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-interface",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",