@fgv/ts-extras 5.1.0-18 → 5.1.0-19

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.
@@ -33,6 +33,7 @@ declare namespace AiAssist {
33
33
  IChatMessage,
34
34
  AiApiFormat,
35
35
  AiImageApiFormat,
36
+ IAiImageModelCapability,
36
37
  IAiProviderDescriptor,
37
38
  IAiAssistProviderConfig,
38
39
  IAiAssistSettings,
@@ -62,6 +63,8 @@ declare namespace AiAssist {
62
63
  allProviderIds,
63
64
  getProviderDescriptors,
64
65
  getProviderDescriptor,
66
+ resolveImageCapability,
67
+ supportsImageGeneration,
65
68
  DEFAULT_MODEL_CAPABILITY_CONFIG,
66
69
  callProviderCompletion,
67
70
  callProxiedCompletion,
@@ -103,9 +106,20 @@ declare const aiAssistSettings: Converter<IAiAssistSettings>;
103
106
 
104
107
  /**
105
108
  * API format categories for image-generation provider routing.
109
+ *
110
+ * @remarks
111
+ * - `'openai-images'` — OpenAI Images API. Routes to `/images/generations`
112
+ * (text-only) or `/images/edits` (when reference images are present).
113
+ * - `'xai-images'` — xAI Images API. Same wire shape as OpenAI but text-only;
114
+ * no reference-image support on grok-2-image.
115
+ * - `'gemini-imagen'` — Google Imagen `:predict` endpoint. Text-only.
116
+ * - `'gemini-image-out'` — Google Gemini chat-style `:generateContent`
117
+ * endpoint that returns image parts (Gemini 2.5 Flash Image / "Nano
118
+ * Banana"). Accepts reference images.
119
+ *
106
120
  * @public
107
121
  */
108
- declare type AiImageApiFormat = 'openai-images' | 'gemini-imagen' | 'xai-images';
122
+ declare type AiImageApiFormat = 'openai-images' | 'gemini-imagen' | 'xai-images' | 'gemini-image-out';
109
123
 
110
124
  /**
111
125
  * Capability vocabulary used to describe what a model can do. Used as both
@@ -277,12 +291,17 @@ declare function callProviderCompletionStream(params: IProviderCompletionStreamP
277
291
  /**
278
292
  * Calls the appropriate image-generation API for a given provider.
279
293
  *
280
- * Routes based on `descriptor.imageApiFormat`:
294
+ * Resolves a {@link IAiImageModelCapability} from
295
+ * {@link IAiProviderDescriptor.imageGeneration} for the requested model and
296
+ * routes by its `format`:
281
297
  * - `'openai-images'` for OpenAI (DALL-E, gpt-image-1)
282
298
  * - `'xai-images'` for xAI Grok image models
283
- * - `'gemini-imagen'` for Google Imagen
299
+ * - `'gemini-imagen'` for Google Imagen `:predict`
300
+ * - `'gemini-image-out'` for Gemini chat-style image output (Nano Banana)
284
301
  *
285
302
  * Image-model selection reuses the existing `'image'` {@link ModelSpecKey}.
303
+ * When `request.referenceImages` is non-empty, the call is rejected up front
304
+ * unless the resolved capability declares `acceptsImageReferenceInput`.
286
305
  *
287
306
  * @param params - Request parameters including descriptor, API key, and prompt
288
307
  * @returns The generated images, or a failure
@@ -353,7 +372,10 @@ declare function callProxiedCompletionStream(proxyUrl: string, params: IProvider
353
372
  * - Error response body: `{error: string}` (surfaced as `proxy: ${error}`)
354
373
  *
355
374
  * The proxy server is responsible for descriptor lookup, model resolution,
356
- * provider dispatch, and response normalization.
375
+ * provider dispatch, and response normalization. When `params.referenceImages`
376
+ * is present, the proxy is also responsible for repackaging it into the
377
+ * upstream wire format (e.g. multipart/form-data for OpenAI `/images/edits`,
378
+ * `inlineData` parts for Gemini `:generateContent`).
357
379
  *
358
380
  * @param proxyUrl - Base URL of the proxy server (e.g. `http://localhost:3001`)
359
381
  * @param params - Same parameters as {@link callProviderImageGeneration}
@@ -480,6 +502,8 @@ declare namespace CryptoUtils {
480
502
  INamedSecret,
481
503
  IEncryptionResult,
482
504
  KeyPairAlgorithm,
505
+ IWrapBytesOptions,
506
+ IWrappedBytes,
483
507
  allKeyPairAlgorithms,
484
508
  KeyDerivationFunction,
485
509
  IKeyDerivationParams,
@@ -1119,6 +1143,16 @@ declare interface IAiImageGenerationParams {
1119
1143
  readonly prompt: string;
1120
1144
  /** Optional generation options. */
1121
1145
  readonly options?: IAiImageGenerationOptions;
1146
+ /**
1147
+ * Optional reference images. When present, the provider will use them as
1148
+ * visual context (e.g. to preserve a character's appearance across multiple
1149
+ * generations). The dispatcher resolves the
1150
+ * {@link AiAssist.IAiImageModelCapability} for the requested model and
1151
+ * rejects the call up front if `acceptsImageReferenceInput` is not set on
1152
+ * the matching capability. An empty array is treated identically to
1153
+ * `undefined`.
1154
+ */
1155
+ readonly referenceImages?: ReadonlyArray<IAiImageAttachment>;
1122
1156
  }
1123
1157
 
1124
1158
  /**
@@ -1130,6 +1164,35 @@ declare interface IAiImageGenerationResponse {
1130
1164
  readonly images: ReadonlyArray<IAiGeneratedImage>;
1131
1165
  }
1132
1166
 
1167
+ /**
1168
+ * Image-generation capability for a model family within a provider. Used as
1169
+ * an entry in {@link IAiProviderDescriptor.imageGeneration}.
1170
+ *
1171
+ * @public
1172
+ */
1173
+ declare interface IAiImageModelCapability {
1174
+ /**
1175
+ * Prefix matched against the resolved image model id. The empty string is
1176
+ * the catch-all and matches every model. When multiple rules' prefixes
1177
+ * match a model id, the longest prefix wins; ties are broken by
1178
+ * first-encountered.
1179
+ */
1180
+ readonly modelPrefix: string;
1181
+ /** API format used to dispatch requests for matching models. */
1182
+ readonly format: AiImageApiFormat;
1183
+ /**
1184
+ * Whether matching models accept reference images via
1185
+ * {@link AiAssist.IAiImageGenerationParams.referenceImages}. When false or
1186
+ * undefined, calls that include reference images are rejected up front.
1187
+ *
1188
+ * @remarks
1189
+ * Per-model constraints beyond ref support (e.g. dall-e-3 ignores edits)
1190
+ * are not validated here and surface as provider 400s, consistent with the
1191
+ * existing image-generation policy.
1192
+ */
1193
+ readonly acceptsImageReferenceInput?: boolean;
1194
+ }
1195
+
1133
1196
  /**
1134
1197
  * Configuration that maps model id patterns to capabilities. Used to
1135
1198
  * augment (or, where the provider supplies no capability info, fully
@@ -1218,15 +1281,27 @@ declare interface IAiProviderDescriptor {
1218
1281
  */
1219
1282
  readonly acceptsImageInput: boolean;
1220
1283
  /**
1221
- * Which image-generation API format this provider uses, or undefined if it
1222
- * does not support image generation.
1284
+ * Image-generation capabilities, scoped to model id prefixes. Empty or
1285
+ * undefined means the provider does not support image generation.
1223
1286
  *
1224
1287
  * @remarks
1288
+ * The dispatcher matches the resolved model id against each rule's
1289
+ * `modelPrefix` and selects the longest match (see
1290
+ * {@link AiAssist.resolveImageCapability}). An empty `modelPrefix` is the
1291
+ * catch-all and matches every model id.
1292
+ *
1293
+ * Multiple entries support providers that host more than one image-API
1294
+ * surface under one baseUrl. Google Gemini is the canonical case: the
1295
+ * `imagen-*` family is predict-only via `:predict`, while
1296
+ * `gemini-2.5-flash-image` uses chat-style `:generateContent` and accepts
1297
+ * reference images. Listing both lets callers pick the right model and the
1298
+ * dispatcher routes accordingly.
1299
+ *
1225
1300
  * Image-model selection reuses the existing `image` {@link ModelSpecKey}.
1226
- * Providers with `imageApiFormat` set should declare a model in
1301
+ * Providers that declare `imageGeneration` should declare a model in
1227
1302
  * `defaultModel.image`, e.g. `{ base: 'gpt-4o', image: 'dall-e-3' }`.
1228
1303
  */
1229
- readonly imageApiFormat?: AiImageApiFormat;
1304
+ readonly imageGeneration?: ReadonlyArray<IAiImageModelCapability>;
1230
1305
  }
1231
1306
 
1232
1307
  /**
@@ -1495,6 +1570,47 @@ declare interface ICryptoProvider {
1495
1570
  * @returns Success with the imported public `CryptoKey`, or Failure with error context.
1496
1571
  */
1497
1572
  importPublicKeyJwk(jwk: JsonWebKey, algorithm: KeyPairAlgorithm): Promise<Result<CryptoKey>>;
1573
+ /**
1574
+ * Wraps `plaintext` for delivery to the holder of the private key paired
1575
+ * with `recipientPublicKey`. Uses ECIES with ECDH P-256, HKDF-SHA256, and
1576
+ * AES-GCM-256.
1577
+ *
1578
+ * Generates a fresh ephemeral keypair per call; the ephemeral private key
1579
+ * is discarded after the shared-secret derive. Only the recipient (with the
1580
+ * matching private key) and the same HKDF parameters can recover
1581
+ * `plaintext`.
1582
+ *
1583
+ * Empty `plaintext` is permitted; the resulting wrap contains only the
1584
+ * 16-byte GCM authentication tag and round-trips back to an empty
1585
+ * `Uint8Array`.
1586
+ * @param plaintext - The bytes to wrap. Any length supported by AES-GCM
1587
+ * (in practice, well below 2^39 - 256 bits).
1588
+ * @param recipientPublicKey - The recipient's ECDH P-256 public `CryptoKey`.
1589
+ * Must have algorithm name `'ECDH'` and named curve `'P-256'`; mismatched
1590
+ * algorithm or curve yields a `Failure` with error context.
1591
+ * @param options - HKDF parameters; see {@link CryptoUtils.IWrapBytesOptions | IWrapBytesOptions}.
1592
+ * @returns `Success` with the wrapped payload, or `Failure` with error context.
1593
+ */
1594
+ wrapBytes(plaintext: Uint8Array, recipientPublicKey: CryptoKey, options: IWrapBytesOptions): Promise<Result<IWrappedBytes>>;
1595
+ /**
1596
+ * Inverse of {@link CryptoUtils.ICryptoProvider.wrapBytes | wrapBytes}.
1597
+ * Recovers the original `plaintext` from a wrapped payload using the
1598
+ * recipient's private key.
1599
+ *
1600
+ * Returns a `Failure` (never throws) on any of:
1601
+ * - Tampered nonce or ciphertext (AES-GCM authentication fails)
1602
+ * - Wrong private key (different shared secret derives a different wrap key)
1603
+ * - Wrong HKDF parameters (different wrap key)
1604
+ * - Malformed `ephemeralPublicKey` JWK
1605
+ * - Malformed base64 in `nonce` or `ciphertext`
1606
+ * @param wrapped - The wrapped payload produced by `wrapBytes`.
1607
+ * @param recipientPrivateKey - The recipient's ECDH P-256 private
1608
+ * `CryptoKey`. Must have algorithm name `'ECDH'` and named curve `'P-256'`,
1609
+ * and key usages including `'deriveKey'` or `'deriveBits'`.
1610
+ * @param options - The same HKDF parameters used at wrap time.
1611
+ * @returns `Success` with the original `plaintext`, or `Failure` with error context.
1612
+ */
1613
+ unwrapBytes(wrapped: IWrappedBytes, recipientPrivateKey: CryptoKey, options: IWrapBytesOptions): Promise<Result<Uint8Array>>;
1498
1614
  }
1499
1615
 
1500
1616
  /**
@@ -2285,6 +2401,59 @@ declare interface IVariableRef {
2285
2401
  readonly isSection: boolean;
2286
2402
  }
2287
2403
 
2404
+ /**
2405
+ * Caller-supplied HKDF parameters that domain-separate one
2406
+ * {@link CryptoUtils.ICryptoProvider.wrapBytes | wrapBytes} call from another.
2407
+ * Two wraps that share recipient but differ on `salt` or `info` derive distinct
2408
+ * wrap keys, so callers should pick values that bind the wrap to its
2409
+ * application context (e.g. a content hash for `salt` and a secret name for
2410
+ * `info`).
2411
+ *
2412
+ * Both fields are required; pass an empty `Uint8Array` if the caller has no
2413
+ * value to bind on a given axis. Silent defaulting would hide protocol
2414
+ * mistakes, so the API does not pick defaults.
2415
+ * @public
2416
+ */
2417
+ declare interface IWrapBytesOptions {
2418
+ /**
2419
+ * HKDF salt. Domain-separates this wrap from others in different contexts.
2420
+ * Caller picks; common choices include a content hash, document id, channel
2421
+ * id, etc.
2422
+ */
2423
+ readonly salt: Uint8Array;
2424
+ /**
2425
+ * HKDF info. Further binds the derived key to a specific use within the
2426
+ * calling application. Caller picks; common choices include a secret name,
2427
+ * message type, or version tag.
2428
+ */
2429
+ readonly info: Uint8Array;
2430
+ }
2431
+
2432
+ /**
2433
+ * Output of {@link CryptoUtils.ICryptoProvider.wrapBytes | wrapBytes}. The
2434
+ * shape is JSON-serializable so it can travel directly over the wire or be
2435
+ * persisted as-is.
2436
+ * @public
2437
+ */
2438
+ declare interface IWrappedBytes {
2439
+ /**
2440
+ * Sender's ephemeral ECDH P-256 public key as a JSON Web Key. The matching
2441
+ * ephemeral private key is dropped after the shared-secret derive.
2442
+ */
2443
+ readonly ephemeralPublicKey: JsonWebKey;
2444
+ /**
2445
+ * AES-GCM nonce, base64-encoded. 12 bytes (96 bits) — the standard AES-GCM
2446
+ * nonce length.
2447
+ */
2448
+ readonly nonce: string;
2449
+ /**
2450
+ * AES-GCM ciphertext concatenated with the 16-byte authentication tag,
2451
+ * base64-encoded. Tampering with either the nonce or the ciphertext causes
2452
+ * unwrap to fail GCM authentication.
2453
+ */
2454
+ readonly ciphertext: string;
2455
+ }
2456
+
2288
2457
  /**
2289
2458
  * Options for YAML serialization, mirroring commonly-used `js-yaml` `DumpOptions`.
2290
2459
  * @public
@@ -3149,6 +3318,25 @@ declare class NodeCryptoProvider implements ICryptoProvider {
3149
3318
  * @returns `Success` with the imported public `CryptoKey`, or `Failure` with an error.
3150
3319
  */
3151
3320
  importPublicKeyJwk(jwk: JsonWebKey, algorithm: KeyPairAlgorithm): Promise<Result<CryptoKey>>;
3321
+ /**
3322
+ * Wraps `plaintext` for the holder of `recipientPublicKey` using
3323
+ * ECIES (ECDH P-256 + HKDF-SHA256 + AES-GCM-256). See
3324
+ * {@link CryptoUtils.ICryptoProvider.wrapBytes | ICryptoProvider.wrapBytes}.
3325
+ * @param plaintext - The bytes to wrap.
3326
+ * @param recipientPublicKey - The recipient's ECDH P-256 public `CryptoKey`.
3327
+ * @param options - HKDF salt and info; see {@link CryptoUtils.IWrapBytesOptions | IWrapBytesOptions}.
3328
+ * @returns `Success` with the wrapped payload, or `Failure` with an error.
3329
+ */
3330
+ wrapBytes(plaintext: Uint8Array, recipientPublicKey: CryptoKey, options: IWrapBytesOptions): Promise<Result<IWrappedBytes>>;
3331
+ /**
3332
+ * Unwraps a payload produced by `wrapBytes` using the recipient's private
3333
+ * key. See {@link CryptoUtils.ICryptoProvider.unwrapBytes | ICryptoProvider.unwrapBytes}.
3334
+ * @param wrapped - The wrapped payload.
3335
+ * @param recipientPrivateKey - The recipient's ECDH P-256 private `CryptoKey`.
3336
+ * @param options - HKDF salt and info matching the wrap call.
3337
+ * @returns `Success` with the original `plaintext`, or `Failure` with an error.
3338
+ */
3339
+ unwrapBytes(wrapped: IWrappedBytes, recipientPrivateKey: CryptoKey, options: IWrapBytesOptions): Promise<Result<Uint8Array>>;
3152
3340
  }
3153
3341
 
3154
3342
  /**
@@ -3378,6 +3566,22 @@ export { RecordJar }
3378
3566
  */
3379
3567
  declare function resolveEffectiveTools(descriptor: IAiProviderDescriptor, settingsTools?: ReadonlyArray<IAiToolEnablement>, perCallTools?: ReadonlyArray<AiServerToolConfig>): ReadonlyArray<AiServerToolConfig>;
3380
3568
 
3569
+ /**
3570
+ * Resolve the image-generation capability that applies to a given model id
3571
+ * for a provider. Returns the entry from
3572
+ * {@link IAiProviderDescriptor.imageGeneration} whose `modelPrefix` is the
3573
+ * longest prefix of `modelId`. Ties are broken by first-encountered, so rule
3574
+ * order does not matter for correctness — only for tie-breaking among rules
3575
+ * with identical-length prefixes (an unusual case).
3576
+ *
3577
+ * @param descriptor - The provider descriptor
3578
+ * @param modelId - The resolved image model id
3579
+ * @returns The matching capability, or `undefined` when no rule matches or
3580
+ * the provider declares no image-generation capabilities.
3581
+ * @public
3582
+ */
3583
+ declare function resolveImageCapability(descriptor: IAiProviderDescriptor, modelId: string): IAiImageModelCapability | undefined;
3584
+
3381
3585
  /**
3382
3586
  * Resolves a {@link ModelSpec} to a concrete model string given an optional context key.
3383
3587
  *
@@ -3401,6 +3605,16 @@ declare function resolveModel(spec: ModelSpec, context?: string): string;
3401
3605
  */
3402
3606
  declare type SecretProvider = (secretName: string) => Promise<Result<Uint8Array>>;
3403
3607
 
3608
+ /**
3609
+ * Whether a provider declares any image-generation capability at all.
3610
+ *
3611
+ * @param descriptor - The provider descriptor
3612
+ * @returns `true` when {@link IAiProviderDescriptor.imageGeneration} has at
3613
+ * least one entry; `false` otherwise.
3614
+ * @public
3615
+ */
3616
+ declare function supportsImageGeneration(descriptor: IAiProviderDescriptor): boolean;
3617
+
3404
3618
  /**
3405
3619
  * Helper function to create a `StringConverter` which converts
3406
3620
  * `unknown` to `string`, applying template conversions supplied at construction time or at
@@ -66,12 +66,17 @@ export interface IProviderImageGenerationParams {
66
66
  /**
67
67
  * Calls the appropriate image-generation API for a given provider.
68
68
  *
69
- * Routes based on `descriptor.imageApiFormat`:
69
+ * Resolves a {@link IAiImageModelCapability} from
70
+ * {@link IAiProviderDescriptor.imageGeneration} for the requested model and
71
+ * routes by its `format`:
70
72
  * - `'openai-images'` for OpenAI (DALL-E, gpt-image-1)
71
73
  * - `'xai-images'` for xAI Grok image models
72
- * - `'gemini-imagen'` for Google Imagen
74
+ * - `'gemini-imagen'` for Google Imagen `:predict`
75
+ * - `'gemini-image-out'` for Gemini chat-style image output (Nano Banana)
73
76
  *
74
77
  * Image-model selection reuses the existing `'image'` {@link ModelSpecKey}.
78
+ * When `request.referenceImages` is non-empty, the call is rejected up front
79
+ * unless the resolved capability declares `acceptsImageReferenceInput`.
75
80
  *
76
81
  * @param params - Request parameters including descriptor, API key, and prompt
77
82
  * @returns The generated images, or a failure
@@ -151,7 +156,10 @@ export declare function callProxiedCompletion(proxyUrl: string, params: IProvide
151
156
  * - Error response body: `{error: string}` (surfaced as `proxy: ${error}`)
152
157
  *
153
158
  * The proxy server is responsible for descriptor lookup, model resolution,
154
- * provider dispatch, and response normalization.
159
+ * provider dispatch, and response normalization. When `params.referenceImages`
160
+ * is present, the proxy is also responsible for repackaging it into the
161
+ * upstream wire format (e.g. multipart/form-data for OpenAI `/images/edits`,
162
+ * `inlineData` parts for Gemini `:generateContent`).
155
163
  *
156
164
  * @param proxyUrl - Base URL of the proxy server (e.g. `http://localhost:3001`)
157
165
  * @param params - Same parameters as {@link callProviderImageGeneration}