@aws-amplify/data-schema 1.17.5 → 1.19.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.
Files changed (28) hide show
  1. package/dist/cjs/SchemaProcessor.js +154 -6
  2. package/dist/cjs/SchemaProcessor.js.map +1 -1
  3. package/dist/cjs/runtime/internals/ai/conversationMessageDeserializers.js +12 -0
  4. package/dist/cjs/runtime/internals/ai/conversationMessageDeserializers.js.map +1 -1
  5. package/dist/cjs/runtime/internals/ai/conversationMessageSerializers.js +12 -0
  6. package/dist/cjs/runtime/internals/ai/conversationMessageSerializers.js.map +1 -1
  7. package/dist/esm/ClientSchema/Core/ClientCustomOperations.d.ts +9 -6
  8. package/dist/esm/CustomOperation.d.ts +1 -1
  9. package/dist/esm/SchemaProcessor.mjs +154 -6
  10. package/dist/esm/SchemaProcessor.mjs.map +1 -1
  11. package/dist/esm/ai/types/ConversationMessageContent.d.ts +14 -3
  12. package/dist/esm/ai/types/contentBlocks.d.ts +8 -0
  13. package/dist/esm/runtime/bridge-types.d.ts +3 -1
  14. package/dist/esm/runtime/internals/ai/conversationMessageDeserializers.mjs +12 -0
  15. package/dist/esm/runtime/internals/ai/conversationMessageDeserializers.mjs.map +1 -1
  16. package/dist/esm/runtime/internals/ai/conversationMessageSerializers.d.ts +8 -0
  17. package/dist/esm/runtime/internals/ai/conversationMessageSerializers.mjs +12 -0
  18. package/dist/esm/runtime/internals/ai/conversationMessageSerializers.mjs.map +1 -1
  19. package/dist/meta/cjs.tsbuildinfo +1 -1
  20. package/package.json +1 -1
  21. package/src/ClientSchema/Core/ClientCustomOperations.ts +14 -15
  22. package/src/CustomOperation.ts +1 -1
  23. package/src/SchemaProcessor.ts +212 -12
  24. package/src/ai/types/ConversationMessageContent.ts +20 -1
  25. package/src/ai/types/contentBlocks.ts +19 -0
  26. package/src/runtime/bridge-types.ts +8 -1
  27. package/src/runtime/internals/ai/conversationMessageDeserializers.ts +13 -0
  28. package/src/runtime/internals/ai/conversationMessageSerializers.ts +16 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws-amplify/data-schema",
3
- "version": "1.17.5",
3
+ "version": "1.19.0",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -9,8 +9,8 @@ import type { AppSyncResolverHandler } from 'aws-lambda';
9
9
  import type { CustomType } from '../../CustomType';
10
10
  import type { FieldTypesOfCustomType } from '../../MappedTypes/ResolveSchema';
11
11
  import type { ResolveRef } from '../utilities/ResolveRef';
12
- import type { EnumType } from '../../EnumType';
13
12
  import { ClientSchemaProperty } from './ClientSchemaProperty';
13
+ import type { ResolveFields } from '../utilities';
14
14
 
15
15
  type CustomOperationSubType<Op extends CustomOperationParamShape> =
16
16
  `custom${Op['typeName']}`;
@@ -38,7 +38,7 @@ export interface ClientCustomOperation<
38
38
  * ```
39
39
  */
40
40
  functionHandler: AppSyncResolverHandler<
41
- CustomOpArguments<Op>,
41
+ CustomOpArguments<Op, RefBag>,
42
42
  // If the final handler is an async function, the Schema['fieldname']['functionhandler']
43
43
  // should have a return type of `void`. This only applies to `functionHandler` and not
44
44
  // `returnType` because `returnType` determines the type returned by the mutation / query
@@ -60,7 +60,7 @@ export interface ClientCustomOperation<
60
60
  * }
61
61
  * ```
62
62
  */
63
- args: CustomOpArguments<Op>;
63
+ args: CustomOpArguments<Op, RefBag>;
64
64
 
65
65
  /**
66
66
  * The return type expected by a lambda function handler.
@@ -84,19 +84,18 @@ export interface ClientCustomOperation<
84
84
 
85
85
  /**
86
86
  * Digs out custom operation arguments, mapped to the intended graphql types.
87
+ * using the existing ResolveFields utility type. This handles:
88
+ * - Basic scalar fields
89
+ * - Enum types
90
+ * - Custom types (including nested structures)
91
+ * - Reference types
87
92
  */
88
- type CustomOpArguments<Shape extends CustomOperationParamShape> =
89
- Shape['arguments'] extends null
90
- ? never
91
- : ResolveFieldRequirements<{
92
- [FieldName in keyof Shape['arguments']]: Shape['arguments'][FieldName] extends BaseModelField<
93
- infer R
94
- >
95
- ? R
96
- : Shape['arguments'][FieldName] extends EnumType<infer Values>
97
- ? Values[number] | null
98
- : never;
99
- }>;
93
+ type CustomOpArguments<
94
+ Shape extends CustomOperationParamShape,
95
+ RefBag extends Record<string, any> = any,
96
+ > = Shape['arguments'] extends null
97
+ ? never
98
+ : ResolveFields<RefBag, Shape['arguments']>;
100
99
 
101
100
  /**
102
101
  * Removes `null | undefined` from the return type if the operation is a subscription,
@@ -29,7 +29,7 @@ type CustomOperationBrand =
29
29
  | typeof subscriptionBrand
30
30
  | typeof generationBrand;
31
31
 
32
- type CustomArguments = Record<string, BaseModelField | EnumType>;
32
+ type CustomArguments = Record<string, BaseModelField | EnumType | CustomType<any> | RefType<any, any>>;
33
33
  type SubscriptionSource = RefType<any, any>;
34
34
  type InternalSubscriptionSource = InternalRef;
35
35
  type CustomReturnType = RefType<any> | CustomType<any>;
@@ -347,6 +347,7 @@ function customOperationToGql(
347
347
  customTypeAuthRules: CustomTypeAuthRules;
348
348
  lambdaFunctionDefinition: LambdaFunctionDefinition;
349
349
  customSqlDataSourceStrategy: CustomSqlDataSourceStrategy | undefined;
350
+ inputTypes: { name: string; fields: Record<string, any> }[];
350
351
  } {
351
352
  const {
352
353
  arguments: fieldArgs,
@@ -442,15 +443,21 @@ function customOperationToGql(
442
443
  });
443
444
  }
444
445
 
445
- if (Object.keys(fieldArgs).length > 0) {
446
- const { gqlFields, implicitTypes: implied } = processFields(
447
- typeName,
448
- fieldArgs,
449
- {},
450
- {},
451
- );
452
- callSignature += `(${gqlFields.join(', ')})`;
453
- implicitTypes.push(...implied);
446
+ const { inputTypes, argDefinitions, collectedEnums } = generateInputTypes(
447
+ typeName,
448
+ fieldArgs,
449
+ getRefType,
450
+ );
451
+
452
+ // Handle collected enums
453
+ for (const [enumName, enumDef] of collectedEnums) {
454
+ if (!implicitTypes.some(([name]) => name === enumName)) {
455
+ implicitTypes.push([enumName, enumDef]);
456
+ }
457
+ }
458
+
459
+ if (argDefinitions.length > 0) {
460
+ callSignature += `(${argDefinitions.join(', ')})`;
454
461
  }
455
462
 
456
463
  const handler = handlers && handlers[0];
@@ -550,6 +557,7 @@ function customOperationToGql(
550
557
  customTypeAuthRules,
551
558
  lambdaFunctionDefinition,
552
559
  customSqlDataSourceStrategy,
560
+ inputTypes,
553
561
  };
554
562
  }
555
563
 
@@ -1316,6 +1324,174 @@ const mergeCustomTypeAuthRules = (
1316
1324
  }
1317
1325
  };
1318
1326
 
1327
+ /**
1328
+ * Generates input types for custom operations in the schema.
1329
+ *
1330
+ * Processes operation arguments to create corresponding input types,
1331
+ * handling referenced and inline custom types, enums, and nested structures.
1332
+ * Manages circular references and prevents duplicate processing.
1333
+ *
1334
+ **/
1335
+
1336
+ function generateInputTypes(
1337
+ operationName: string,
1338
+ args: Record<string, any>,
1339
+ getRefType: (name: string, referrerName?: string) => GetRef,
1340
+ ): {
1341
+ inputTypes: { name: string; fields: Record<string, any> }[];
1342
+ argDefinitions: string[];
1343
+ collectedEnums: Map<string, any>;
1344
+ } {
1345
+ const inputTypes: {
1346
+ name: string;
1347
+ fields: Record<string, any>;
1348
+ }[] = [];
1349
+ const argDefinitions: string[] = [];
1350
+ const collectedEnums: Map<string, any> = new Map();
1351
+ const processedTypes = new Set<string>(); // Track processed types to avoid duplicates
1352
+
1353
+ const processNonScalarFields = (
1354
+ fields: Record<string, any>,
1355
+ originalTypeName: string,
1356
+ isParentRef: boolean = false,
1357
+ parentChain: string[] = [], // Used to detect circular references
1358
+ ): Record<string, any> => {
1359
+ const processedFields: Record<string, any> = {};
1360
+ for (const [fieldName, fieldDef] of Object.entries(fields)) {
1361
+ if (isRefField(fieldDef)) {
1362
+ const refType = getRefType(fieldDef.data.link, originalTypeName);
1363
+ if (refType.type === 'CustomType') {
1364
+ const nestedInputTypeName = `${fieldDef.data.link}Input`;
1365
+ processedFields[fieldName] = {
1366
+ data: { type: 'ref', link: nestedInputTypeName },
1367
+ };
1368
+
1369
+ // Process the nested type if it hasn't been processed and isn't a circular reference
1370
+ if (
1371
+ !parentChain.includes(nestedInputTypeName) &&
1372
+ !processedTypes.has(nestedInputTypeName)
1373
+ ) {
1374
+ processedTypes.add(nestedInputTypeName);
1375
+ const nestedFields = processNonScalarFields(
1376
+ refType.def.data.fields,
1377
+ fieldDef.data.link,
1378
+ true,
1379
+ [...parentChain, nestedInputTypeName],
1380
+ );
1381
+ inputTypes.push({
1382
+ name: nestedInputTypeName,
1383
+ fields: nestedFields,
1384
+ });
1385
+ }
1386
+ } else if (refType.type === 'Enum') {
1387
+ processedFields[fieldName] = {
1388
+ data: { type: 'ref', link: fieldDef.data.link },
1389
+ };
1390
+ } else {
1391
+ throw new Error(
1392
+ `Unsupported reference type '${refType.type}' for field '${fieldName}'. ` +
1393
+ `Only references to CustomType and Enum are supported.`,
1394
+ );
1395
+ }
1396
+ } else if (isCustomType(fieldDef)) {
1397
+ // Handle inline custom types
1398
+ const nestedInputTypeName = `${capitalize(originalTypeName)}${capitalize(fieldName)}Input`;
1399
+ processedFields[fieldName] = {
1400
+ data: { type: 'ref', link: nestedInputTypeName },
1401
+ };
1402
+
1403
+ if (!processedTypes.has(nestedInputTypeName)) {
1404
+ processedTypes.add(nestedInputTypeName);
1405
+ const nestedFields = processNonScalarFields(
1406
+ fieldDef.data.fields,
1407
+ `${capitalize(originalTypeName)}${capitalize(fieldName)}`,
1408
+ isParentRef,
1409
+ [...parentChain, nestedInputTypeName],
1410
+ );
1411
+ inputTypes.push({
1412
+ name: nestedInputTypeName,
1413
+ fields: nestedFields,
1414
+ });
1415
+ }
1416
+ } else if (isEnumType(fieldDef)) {
1417
+ // Handle enum types
1418
+ const enumName = `${capitalize(originalTypeName)}${capitalize(fieldName)}`;
1419
+ if (!collectedEnums.has(enumName) && !isParentRef) {
1420
+ collectedEnums.set(enumName, fieldDef);
1421
+ }
1422
+ processedFields[fieldName] = { data: { type: 'ref', link: enumName } };
1423
+ } else {
1424
+ processedFields[fieldName] = fieldDef;
1425
+ }
1426
+ }
1427
+ return processedFields;
1428
+ };
1429
+
1430
+ // Process top-level arguments
1431
+ for (const [argName, argDef] of Object.entries(args)) {
1432
+ if (isRefField(argDef)) {
1433
+ const refType = getRefType(argDef.data.link, operationName);
1434
+ if (refType.type === 'CustomType') {
1435
+ const inputTypeName = `${argDef.data.link}Input`;
1436
+ argDefinitions.push(`${argName}: ${inputTypeName}`);
1437
+
1438
+ // Process the input type if it hasn't been processed yet
1439
+ if (!processedTypes.has(inputTypeName)) {
1440
+ processedTypes.add(inputTypeName);
1441
+ const fields = processNonScalarFields(
1442
+ refType.def.data.fields,
1443
+ argDef.data.link,
1444
+ true,
1445
+ [inputTypeName],
1446
+ );
1447
+ inputTypes.push({
1448
+ name: inputTypeName,
1449
+ fields,
1450
+ });
1451
+ }
1452
+ } else if (refType.type === 'Enum') {
1453
+ argDefinitions.push(`${argName}: ${argDef.data.link}`);
1454
+ } else {
1455
+ throw new Error(
1456
+ `Unsupported reference type '${refType.type}' for argument '${argName}' in '${operationName}'. ` +
1457
+ `Only references to CustomType and Enum are supported.`,
1458
+ );
1459
+ }
1460
+ } else if (isEnumType(argDef)) {
1461
+ // Handle top-level enum arguments
1462
+ const enumName = `${capitalize(operationName)}${capitalize(argName)}`;
1463
+ if (!collectedEnums.has(enumName)) {
1464
+ collectedEnums.set(enumName, argDef);
1465
+ }
1466
+ argDefinitions.push(`${argName}: ${enumName}`);
1467
+ } else if (isCustomType(argDef)) {
1468
+ // Handle top-level custom type arguments
1469
+ const inputTypeName = `${capitalize(operationName)}${capitalize(argName)}Input`;
1470
+ argDefinitions.push(`${argName}: ${inputTypeName}`);
1471
+
1472
+ if (!processedTypes.has(inputTypeName)) {
1473
+ processedTypes.add(inputTypeName);
1474
+ const fields = processNonScalarFields(
1475
+ argDef.data.fields,
1476
+ `${capitalize(operationName)}${capitalize(argName)}`,
1477
+ false,
1478
+ [inputTypeName],
1479
+ );
1480
+ inputTypes.push({
1481
+ name: inputTypeName,
1482
+ fields,
1483
+ });
1484
+ }
1485
+ } else if (isScalarField(argDef)) {
1486
+ argDefinitions.push(`${argName}: ${scalarFieldToGql(argDef.data)}`);
1487
+ } else {
1488
+ throw new Error(`Unsupported argument type for ${argName}`);
1489
+ }
1490
+ }
1491
+
1492
+ return { inputTypes, argDefinitions, collectedEnums };
1493
+ }
1494
+
1319
1495
  const schemaPreprocessor = (
1320
1496
  schema: InternalSchema,
1321
1497
  ): {
@@ -1326,7 +1502,6 @@ const schemaPreprocessor = (
1326
1502
  customSqlDataSourceStrategies?: CustomSqlDataSourceStrategy[];
1327
1503
  } => {
1328
1504
  const gqlModels: string[] = [];
1329
-
1330
1505
  const customQueries = [];
1331
1506
  const customMutations = [];
1332
1507
  const customSubscriptions = [];
@@ -1374,6 +1549,7 @@ const schemaPreprocessor = (
1374
1549
  );
1375
1550
 
1376
1551
  const getRefType = getRefTypeForSchema(schema);
1552
+ const uniqueInputTypes = new Map<string, Record<string, any>>();
1377
1553
 
1378
1554
  for (const [typeName, typeDef] of topLevelTypes) {
1379
1555
  const mostRelevantAuthRules: Authorization<any, any, any>[] =
@@ -1449,6 +1625,7 @@ const schemaPreprocessor = (
1449
1625
  jsFunctionForField,
1450
1626
  lambdaFunctionDefinition,
1451
1627
  customSqlDataSourceStrategy,
1628
+ inputTypes,
1452
1629
  } = transformCustomOperations(
1453
1630
  typeDef,
1454
1631
  typeName,
@@ -1457,6 +1634,13 @@ const schemaPreprocessor = (
1457
1634
  getRefType,
1458
1635
  );
1459
1636
 
1637
+ // Process input types without duplicates
1638
+ for (const { name, fields } of inputTypes) {
1639
+ if (!uniqueInputTypes.has(name)) {
1640
+ uniqueInputTypes.set(name, fields);
1641
+ }
1642
+ }
1643
+
1460
1644
  topLevelTypes.push(...implicitTypes);
1461
1645
 
1462
1646
  mergeCustomTypeAuthRules(
@@ -1542,7 +1726,6 @@ const schemaPreprocessor = (
1542
1726
  undefined,
1543
1727
  databaseEngine,
1544
1728
  );
1545
-
1546
1729
  topLevelTypes.push(...implicitTypes);
1547
1730
 
1548
1731
  const joined = gqlFields.join('\n ');
@@ -1622,6 +1805,22 @@ const schemaPreprocessor = (
1622
1805
  }
1623
1806
  }
1624
1807
 
1808
+ // Generate input types after processing all custom operations
1809
+ for (const [name, fields] of uniqueInputTypes) {
1810
+ const { gqlFields } = processFields(
1811
+ name,
1812
+ fields,
1813
+ {},
1814
+ {},
1815
+ undefined,
1816
+ undefined,
1817
+ undefined,
1818
+ databaseEngine,
1819
+ );
1820
+ const inputTypeDefinition = `input ${name} {\n ${gqlFields.join('\n ')}\n}`;
1821
+ gqlModels.push(inputTypeDefinition);
1822
+ }
1823
+
1625
1824
  const customOperations = {
1626
1825
  queries: customQueries,
1627
1826
  mutations: customMutations,
@@ -1632,7 +1831,6 @@ const schemaPreprocessor = (
1632
1831
  if (shouldAddConversationTypes) {
1633
1832
  gqlModels.push(CONVERSATION_SCHEMA_GRAPHQL_TYPES);
1634
1833
  }
1635
-
1636
1834
  const processedSchema = gqlModels.join('\n\n');
1637
1835
 
1638
1836
  return {
@@ -1935,6 +2133,7 @@ function transformCustomOperations(
1935
2133
  customTypeAuthRules,
1936
2134
  lambdaFunctionDefinition,
1937
2135
  customSqlDataSourceStrategy,
2136
+ inputTypes,
1938
2137
  } = customOperationToGql(
1939
2138
  typeName,
1940
2139
  typeDef,
@@ -1951,6 +2150,7 @@ function transformCustomOperations(
1951
2150
  jsFunctionForField,
1952
2151
  lambdaFunctionDefinition,
1953
2152
  customSqlDataSourceStrategy,
2153
+ inputTypes,
1954
2154
  };
1955
2155
  }
1956
2156
 
@@ -1,11 +1,17 @@
1
1
  // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- import { ImageBlock, ToolResultBlock, ToolUseBlock } from './contentBlocks';
4
+ import {
5
+ ImageBlock,
6
+ DocumentBlock,
7
+ ToolResultBlock,
8
+ ToolUseBlock,
9
+ } from './contentBlocks';
5
10
 
6
11
  export interface ConversationMessageTextContent {
7
12
  text: string;
8
13
  image?: never;
14
+ document?: never;
9
15
  toolUse?: never;
10
16
  toolResult?: never;
11
17
  }
@@ -13,13 +19,23 @@ export interface ConversationMessageTextContent {
13
19
  export interface ConversationMessageImageContent {
14
20
  text?: never;
15
21
  image: ImageBlock;
22
+ document?: never;
16
23
  toolUse?: never;
17
24
  toolResult?: never;
18
25
  }
19
26
 
27
+ export interface ConversationMessageDocumentContent {
28
+ text?: never;
29
+ image?: never;
30
+ toolUse?: never;
31
+ toolResult?: never;
32
+ document: DocumentBlock;
33
+ }
34
+
20
35
  export interface ConversationMessageToolUseContent {
21
36
  text?: never;
22
37
  image?: never;
38
+ document?: never;
23
39
  toolUse: ToolUseBlock;
24
40
  toolResult?: never;
25
41
  }
@@ -27,6 +43,7 @@ export interface ConversationMessageToolUseContent {
27
43
  export interface ConversationMessageToolResultContent {
28
44
  text?: never;
29
45
  image?: never;
46
+ document?: never;
30
47
  toolUse?: never;
31
48
  toolResult: ToolResultBlock;
32
49
  }
@@ -34,10 +51,12 @@ export interface ConversationMessageToolResultContent {
34
51
  export type ConversationMessageContent =
35
52
  | ConversationMessageTextContent
36
53
  | ConversationMessageImageContent
54
+ | ConversationMessageDocumentContent
37
55
  | ConversationMessageToolUseContent
38
56
  | ConversationMessageToolResultContent;
39
57
 
40
58
  export type ConversationSendMessageInputContent =
41
59
  | Omit<ConversationMessageTextContent, 'toolUse'>
42
60
  | Omit<ConversationMessageImageContent, 'toolUse'>
61
+ | Omit<ConversationMessageDocumentContent, 'toolUse'>
43
62
  | Omit<ConversationMessageToolResultContent, 'toolUse'>;
@@ -8,12 +8,31 @@ interface BytesImageSource {
8
8
  bytes: Uint8Array;
9
9
  }
10
10
 
11
+ interface BytesDocumentSource {
12
+ bytes: Uint8Array;
13
+ }
14
+
11
15
  // common content blocks
12
16
  export interface ImageBlock {
13
17
  format: 'gif' | 'jpeg' | 'png' | 'webp';
14
18
  source: BytesImageSource;
15
19
  }
16
20
 
21
+ export interface DocumentBlock {
22
+ format:
23
+ | 'pdf'
24
+ | 'csv'
25
+ | 'doc'
26
+ | 'docx'
27
+ | 'xls'
28
+ | 'xlsx'
29
+ | 'html'
30
+ | 'txt'
31
+ | 'md';
32
+ name: string;
33
+ source: BytesDocumentSource;
34
+ }
35
+
17
36
  export interface ToolUseBlock {
18
37
  toolUseId: string;
19
38
  name: string;
@@ -16,6 +16,8 @@ import { Observable } from 'rxjs';
16
16
  import { CustomHeaders, ModelSortDirection } from './client';
17
17
 
18
18
  import { AiAction, AiCategory } from './internals/ai/getCustomUserAgentDetails';
19
+ import { CustomType } from '../CustomType';
20
+ import { RefType } from '../RefType';
19
21
 
20
22
  export declare namespace AmplifyServer {
21
23
  export interface ContextToken {
@@ -240,7 +242,12 @@ export type FieldType =
240
242
  | ModelFieldType
241
243
  | NonModelFieldType;
242
244
 
243
- export type InputFieldType = ScalarType | EnumType | InputType;
245
+ export type InputFieldType =
246
+ | ScalarType
247
+ | EnumType
248
+ | InputType
249
+ | CustomType<any>
250
+ | RefType<any, any>;
244
251
 
245
252
  export type FieldAttribute = ModelAttribute;
246
253
 
@@ -11,6 +11,9 @@ export const deserializeContent = (
11
11
  if (block.image) {
12
12
  return deserializeImageBlock(block);
13
13
  }
14
+ if (block.document) {
15
+ return deserializeDocumentBlock(block);
16
+ }
14
17
  if (block.toolUse) {
15
18
  return deserializeToolUseBlock(block);
16
19
  }
@@ -30,6 +33,16 @@ const deserializeImageBlock = ({ image }: Record<'image', any>) => ({
30
33
  },
31
34
  });
32
35
 
36
+ const deserializeDocumentBlock = ({ document }: Record<'document', any>) => ({
37
+ document: {
38
+ ...document,
39
+ source: {
40
+ ...document.source,
41
+ bytes: fromBase64(document.source.bytes),
42
+ },
43
+ },
44
+ });
45
+
33
46
  const deserializeJsonBlock = ({ json }: Record<'json', any>) => ({
34
47
  json: JSON.parse(json),
35
48
  });
@@ -5,6 +5,7 @@ import { toBase64 } from '@smithy/util-base64';
5
5
  import type {
6
6
  ConversationMessageContent,
7
7
  ConversationMessageImageContent,
8
+ ConversationMessageDocumentContent,
8
9
  ConversationMessageToolResultContent,
9
10
  } from '../../../ai/types/ConversationMessageContent';
10
11
  import type { ToolConfiguration } from '../../../ai/types/ToolConfiguration';
@@ -18,6 +19,9 @@ export const serializeContent = (content: ConversationMessageContent[]) =>
18
19
  if (block.image) {
19
20
  return serializeImageBlock(block);
20
21
  }
22
+ if (block.document) {
23
+ return serializeDocumentBlock(block);
24
+ }
21
25
  if (block.toolResult) {
22
26
  return serializeToolResultBlock(block);
23
27
  }
@@ -46,6 +50,18 @@ const serializeImageBlock = ({ image }: ConversationMessageImageContent) => ({
46
50
  },
47
51
  });
48
52
 
53
+ const serializeDocumentBlock = ({
54
+ document,
55
+ }: ConversationMessageDocumentContent) => ({
56
+ document: {
57
+ ...document,
58
+ source: {
59
+ ...document.source,
60
+ bytes: toBase64(document.source.bytes),
61
+ },
62
+ },
63
+ });
64
+
49
65
  const serializeJsonBlock = ({ json }: ToolResultJsonContent) => ({
50
66
  json: JSON.stringify(json),
51
67
  });