@tangle-network/agent-interface 0.17.1 → 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.
@@ -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.1",
3
+ "version": "0.18.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",