Repository: vercel-labs/ai
File: packages/ai/src/generate-image/generate-image.ts (TypeScript)

Code before:
        if (providerName === 'gateway') {
          const currentEntry = providerMetadata[providerName];
          if (currentEntry != null && typeof currentEntry === 'object') {
            providerMetadata[providerName] = {
              ...(currentEntry as object),
              ...metadata,
            } as ImageModelV3ProviderMetadata[string];
          } else {
            providerMetadata[providerName] =
              metadata as ImageModelV3ProviderMetadata[string];
          }
          const imagesValue = (
            providerMetadata[providerName] as { images?: unknown }
          ).images;
          if (Array.isArray(imagesValue) && imagesValue.length === 0) {
            delete (providerMetadata[providerName] as { images?: unknown })
              .images;
          }
        } else {
          providerMetadata[providerName] ??= { images: [] };
          providerMetadata[providerName].images.push(
            ...result.providerMetadata[providerName].images,
          );

          // Accumulate token details across calls
          const incoming = metadata as Record<string, unknown>;
          if (incoming.inputTokensDetails != null) {
            const incomingDetails = incoming.inputTokensDetails as {
              imageTokens?: number;
              textTokens?: number;
            };
            const existing = (
              providerMetadata[providerName] as Record<string, unknown>
            ).inputTokensDetails as
              | { imageTokens?: number; textTokens?: number }
              | undefined;

            (
              providerMetadata[providerName] as Record<string, unknown>
            ).inputTokensDetails = {
              imageTokens:
                (existing?.imageTokens ?? 0) +
                (incomingDetails.imageTokens ?? 0),
              textTokens:
                (existing?.textTokens ?? 0) + (incomingDetails.textTokens ?? 0),
            };
          }
        }
      }
    }


Review comment (suggestion):
@gr2m for video generation I have learned from this challenge by including the provider metadata for all responses. I wonder whether we can start doing the same here instead of continuing to tack on more custom specific accumulations. It may be a larger change though, for us to consider.

See for example https://github.com/vercel/ai/blob/main/packages/ai/src/generate-video/generate-video-result.ts#L30

There is also more discussion of the issue here: https://github.com/vercel/ai/pull/10716

Code after:
        if (providerName === 'gateway') {
          const currentEntry = providerMetadata[providerName];
          if (currentEntry != null && typeof currentEntry === 'object') {
            providerMetadata[providerName] = {
              ...(currentEntry as object),
              ...metadata,
            } as ImageModelV3ProviderMetadata[string];
          } else {
            providerMetadata[providerName] =
              metadata as ImageModelV3ProviderMetadata[string];
          }
          const imagesValue = (
            providerMetadata[providerName] as { images?: unknown }
          ).images;
          if (Array.isArray(imagesValue) && imagesValue.length === 0) {
            delete (providerMetadata[providerName] as { images?: unknown })
              .images;
          }
        } else {
          providerMetadata[providerName] ??= { images: [] };
          providerMetadata[providerName].images.push(
            ...result.providerMetadata[providerName].images,
          );
        }
      }
    }

    responses.push(result.response);
  }

  logWarnings({ warnings, provider: model.provider, model: model.modelId });

  if (!images.length) {
    throw new NoImageGeneratedError({ responses });
  }

  return new DefaultGenerateImageResult({
    images,
    warnings,
    responses,
    providerMetadata,
    usage: totalUsage,
  });
}

class DefaultGenerateImageResult implements GenerateImageResult {
  readonly images: Array<GeneratedFile>;
  readonly warnings: Array<Warning>;
  readonly responses: Array<ImageModelResponseMetadata>;
  readonly providerMetadata: ImageModelV3ProviderMetadata;
  readonly usage: ImageModelUsage;