qtype 0.0.16__py3-none-any.whl → 0.1.1__py3-none-any.whl

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 (128) hide show
  1. qtype/application/commons/tools.py +1 -1
  2. qtype/application/converters/tools_from_api.py +5 -5
  3. qtype/application/converters/tools_from_module.py +2 -2
  4. qtype/application/converters/types.py +14 -43
  5. qtype/application/documentation.py +1 -1
  6. qtype/application/facade.py +94 -73
  7. qtype/base/types.py +227 -7
  8. qtype/cli.py +4 -0
  9. qtype/commands/convert.py +20 -8
  10. qtype/commands/generate.py +19 -27
  11. qtype/commands/run.py +73 -36
  12. qtype/commands/serve.py +74 -54
  13. qtype/commands/validate.py +34 -8
  14. qtype/commands/visualize.py +46 -22
  15. qtype/dsl/__init__.py +6 -5
  16. qtype/dsl/custom_types.py +1 -1
  17. qtype/dsl/domain_types.py +65 -5
  18. qtype/dsl/linker.py +384 -0
  19. qtype/dsl/loader.py +315 -0
  20. qtype/dsl/model.py +612 -363
  21. qtype/dsl/parser.py +200 -0
  22. qtype/dsl/types.py +50 -0
  23. qtype/interpreter/api.py +57 -136
  24. qtype/interpreter/auth/aws.py +19 -9
  25. qtype/interpreter/auth/generic.py +93 -16
  26. qtype/interpreter/base/base_step_executor.py +436 -0
  27. qtype/interpreter/base/batch_step_executor.py +171 -0
  28. qtype/interpreter/base/exceptions.py +50 -0
  29. qtype/interpreter/base/executor_context.py +74 -0
  30. qtype/interpreter/base/factory.py +117 -0
  31. qtype/interpreter/base/progress_tracker.py +110 -0
  32. qtype/interpreter/base/secrets.py +339 -0
  33. qtype/interpreter/base/step_cache.py +74 -0
  34. qtype/interpreter/base/stream_emitter.py +469 -0
  35. qtype/interpreter/conversions.py +462 -22
  36. qtype/interpreter/converters.py +77 -0
  37. qtype/interpreter/endpoints.py +355 -0
  38. qtype/interpreter/executors/agent_executor.py +242 -0
  39. qtype/interpreter/executors/aggregate_executor.py +93 -0
  40. qtype/interpreter/executors/decoder_executor.py +163 -0
  41. qtype/interpreter/executors/doc_to_text_executor.py +112 -0
  42. qtype/interpreter/executors/document_embedder_executor.py +107 -0
  43. qtype/interpreter/executors/document_search_executor.py +122 -0
  44. qtype/interpreter/executors/document_source_executor.py +118 -0
  45. qtype/interpreter/executors/document_splitter_executor.py +105 -0
  46. qtype/interpreter/executors/echo_executor.py +63 -0
  47. qtype/interpreter/executors/field_extractor_executor.py +160 -0
  48. qtype/interpreter/executors/file_source_executor.py +101 -0
  49. qtype/interpreter/executors/file_writer_executor.py +110 -0
  50. qtype/interpreter/executors/index_upsert_executor.py +228 -0
  51. qtype/interpreter/executors/invoke_embedding_executor.py +92 -0
  52. qtype/interpreter/executors/invoke_flow_executor.py +51 -0
  53. qtype/interpreter/executors/invoke_tool_executor.py +358 -0
  54. qtype/interpreter/executors/llm_inference_executor.py +272 -0
  55. qtype/interpreter/executors/prompt_template_executor.py +78 -0
  56. qtype/interpreter/executors/sql_source_executor.py +106 -0
  57. qtype/interpreter/executors/vector_search_executor.py +91 -0
  58. qtype/interpreter/flow.py +159 -22
  59. qtype/interpreter/metadata_api.py +115 -0
  60. qtype/interpreter/resource_cache.py +5 -4
  61. qtype/interpreter/rich_progress.py +225 -0
  62. qtype/interpreter/stream/chat/__init__.py +15 -0
  63. qtype/interpreter/stream/chat/converter.py +391 -0
  64. qtype/interpreter/{chat → stream/chat}/file_conversions.py +2 -2
  65. qtype/interpreter/stream/chat/ui_request_to_domain_type.py +140 -0
  66. qtype/interpreter/stream/chat/vercel.py +609 -0
  67. qtype/interpreter/stream/utils/__init__.py +15 -0
  68. qtype/interpreter/stream/utils/build_vercel_ai_formatter.py +74 -0
  69. qtype/interpreter/stream/utils/callback_to_stream.py +66 -0
  70. qtype/interpreter/stream/utils/create_streaming_response.py +18 -0
  71. qtype/interpreter/stream/utils/default_chat_extract_text.py +20 -0
  72. qtype/interpreter/stream/utils/error_streaming_response.py +20 -0
  73. qtype/interpreter/telemetry.py +135 -8
  74. qtype/interpreter/tools/__init__.py +5 -0
  75. qtype/interpreter/tools/function_tool_helper.py +265 -0
  76. qtype/interpreter/types.py +330 -0
  77. qtype/interpreter/typing.py +83 -89
  78. qtype/interpreter/ui/404/index.html +1 -1
  79. qtype/interpreter/ui/404.html +1 -1
  80. qtype/interpreter/ui/_next/static/{nUaw6_IwRwPqkzwe5s725 → 20HoJN6otZ_LyHLHpCPE6}/_buildManifest.js +1 -1
  81. qtype/interpreter/ui/_next/static/chunks/{393-8fd474427f8e19ce.js → 434-b2112d19f25c44ff.js} +3 -3
  82. qtype/interpreter/ui/_next/static/chunks/app/page-8c67d16ac90d23cb.js +1 -0
  83. qtype/interpreter/ui/_next/static/chunks/ba12c10f-546f2714ff8abc66.js +1 -0
  84. qtype/interpreter/ui/_next/static/css/8a8d1269e362fef7.css +3 -0
  85. qtype/interpreter/ui/icon.png +0 -0
  86. qtype/interpreter/ui/index.html +1 -1
  87. qtype/interpreter/ui/index.txt +4 -4
  88. qtype/semantic/checker.py +583 -0
  89. qtype/semantic/generate.py +262 -83
  90. qtype/semantic/loader.py +95 -0
  91. qtype/semantic/model.py +436 -159
  92. qtype/semantic/resolver.py +63 -19
  93. qtype/semantic/visualize.py +28 -31
  94. {qtype-0.0.16.dist-info → qtype-0.1.1.dist-info}/METADATA +16 -3
  95. qtype-0.1.1.dist-info/RECORD +135 -0
  96. qtype/dsl/base_types.py +0 -38
  97. qtype/dsl/validator.py +0 -465
  98. qtype/interpreter/batch/__init__.py +0 -0
  99. qtype/interpreter/batch/file_sink_source.py +0 -162
  100. qtype/interpreter/batch/flow.py +0 -95
  101. qtype/interpreter/batch/sql_source.py +0 -92
  102. qtype/interpreter/batch/step.py +0 -74
  103. qtype/interpreter/batch/types.py +0 -41
  104. qtype/interpreter/batch/utils.py +0 -178
  105. qtype/interpreter/chat/chat_api.py +0 -237
  106. qtype/interpreter/chat/vercel.py +0 -314
  107. qtype/interpreter/exceptions.py +0 -10
  108. qtype/interpreter/step.py +0 -67
  109. qtype/interpreter/steps/__init__.py +0 -0
  110. qtype/interpreter/steps/agent.py +0 -114
  111. qtype/interpreter/steps/condition.py +0 -36
  112. qtype/interpreter/steps/decoder.py +0 -88
  113. qtype/interpreter/steps/llm_inference.py +0 -171
  114. qtype/interpreter/steps/prompt_template.py +0 -54
  115. qtype/interpreter/steps/search.py +0 -24
  116. qtype/interpreter/steps/tool.py +0 -219
  117. qtype/interpreter/streaming_helpers.py +0 -123
  118. qtype/interpreter/ui/_next/static/chunks/app/page-7e26b6156cfb55d3.js +0 -1
  119. qtype/interpreter/ui/_next/static/chunks/ba12c10f-22556063851a6df2.js +0 -1
  120. qtype/interpreter/ui/_next/static/css/b40532b0db09cce3.css +0 -3
  121. qtype/interpreter/ui/favicon.ico +0 -0
  122. qtype/loader.py +0 -390
  123. qtype-0.0.16.dist-info/RECORD +0 -106
  124. /qtype/interpreter/ui/_next/static/{nUaw6_IwRwPqkzwe5s725 → 20HoJN6otZ_LyHLHpCPE6}/_ssgManifest.js +0 -0
  125. {qtype-0.0.16.dist-info → qtype-0.1.1.dist-info}/WHEEL +0 -0
  126. {qtype-0.0.16.dist-info → qtype-0.1.1.dist-info}/entry_points.txt +0 -0
  127. {qtype-0.0.16.dist-info → qtype-0.1.1.dist-info}/licenses/LICENSE +0 -0
  128. {qtype-0.0.16.dist-info → qtype-0.1.1.dist-info}/top_level.txt +0 -0
qtype/dsl/domain_types.py CHANGED
@@ -5,7 +5,7 @@ from typing import Any
5
5
 
6
6
  from pydantic import Field
7
7
 
8
- from qtype.dsl.base_types import PrimitiveTypeEnum, StrictBaseModel
8
+ from qtype.base.types import PrimitiveTypeEnum, StrictBaseModel
9
9
 
10
10
 
11
11
  class Embedding(StrictBaseModel):
@@ -14,11 +14,12 @@ class Embedding(StrictBaseModel):
14
14
  vector: list[float] = Field(
15
15
  ..., description="The vector representation of the embedding."
16
16
  )
17
- source_text: str | None = Field(
18
- None, description="The original text that was embedded."
17
+ content: Any | None = Field(
18
+ None, description="The original content that was embedded."
19
19
  )
20
- metadata: dict[str, str] | None = Field(
21
- None, description="Optional metadata associated with the embedding."
20
+ metadata: dict[str, Any] = Field(
21
+ default_factory=dict,
22
+ description="Metadata associated with the embedding.",
22
23
  )
23
24
 
24
25
 
@@ -57,3 +58,62 @@ class ChatMessage(StrictBaseModel):
57
58
  ...,
58
59
  description="The content blocks of the chat message, which can include text, images, or other media.",
59
60
  )
61
+
62
+
63
+ class RAGDocument(StrictBaseModel):
64
+ """A standard, built-in representation of a document used in Retrieval-Augmented Generation (RAG)."""
65
+
66
+ content: Any = Field(..., description="The main content of the document.")
67
+ file_id: str = Field(..., description="An unique identifier for the file.")
68
+ file_name: str = Field(..., description="The name of the file.")
69
+ uri: str | None = Field(
70
+ None, description="The URI where the document can be found."
71
+ )
72
+ metadata: dict[str, Any] = Field(
73
+ default_factory=dict,
74
+ description="Metadata associated with the document.",
75
+ )
76
+ type: PrimitiveTypeEnum = Field(
77
+ ...,
78
+ description="The type of the document content (e.g., 'text', 'image').",
79
+ )
80
+
81
+
82
+ class RAGChunk(Embedding):
83
+ """A standard, built-in representation of a chunk of a document used in Retrieval-Augmented Generation (RAG)."""
84
+
85
+ chunk_id: str = Field(
86
+ ..., description="An unique identifier for the chunk."
87
+ )
88
+ document_id: str = Field(
89
+ ..., description="The identifier of the parent document."
90
+ )
91
+ vector: list[float] | None = Field(
92
+ None, description="Optional vector embedding for the chunk."
93
+ )
94
+
95
+
96
+ class RAGSearchResult(StrictBaseModel):
97
+ """A standard, built-in representation of a search result from a RAG vector search."""
98
+
99
+ chunk: RAGChunk = Field(
100
+ ..., description="The RAG chunk returned as a search result."
101
+ )
102
+ score: float = Field(
103
+ ...,
104
+ description="The similarity score of the chunk with respect to the query.",
105
+ )
106
+
107
+
108
+ class AggregateStats(StrictBaseModel):
109
+ """A standard, built-in representation of aggregate statistics."""
110
+
111
+ num_successful: int = Field(
112
+ ..., description="The count of successful messages processed."
113
+ )
114
+ num_failed: int = Field(
115
+ ..., description="The count of failed messages processed."
116
+ )
117
+ num_total: int = Field(
118
+ ..., description="The total count of messages processed."
119
+ )
qtype/dsl/linker.py ADDED
@@ -0,0 +1,384 @@
1
+ from typing import Any, Dict, Type
2
+
3
+ from pydantic import BaseModel, RootModel
4
+
5
+ import qtype.base.types as base_types
6
+ import qtype.dsl.domain_types
7
+ import qtype.dsl.model as dsl
8
+
9
+
10
+ class QTypeValidationError(Exception):
11
+ """Raised when there's an error during QType validation."""
12
+
13
+ pass
14
+
15
+
16
+ class DuplicateComponentError(QTypeValidationError):
17
+ """Raised when there are duplicate components with the same ID."""
18
+
19
+ def __init__(
20
+ self,
21
+ obj_id: str,
22
+ found_obj: qtype.dsl.domain_types.StrictBaseModel,
23
+ existing_obj: qtype.dsl.domain_types.StrictBaseModel,
24
+ ):
25
+ super().__init__(
26
+ f"Duplicate component with ID {obj_id} found:\n"
27
+ + str(found_obj.model_dump_json())
28
+ + "\nAlready exists:\n"
29
+ + str(existing_obj.model_dump_json())
30
+ )
31
+
32
+
33
+ class ComponentNotFoundError(QTypeValidationError):
34
+ """Raised when a component is not found in the DSL Application."""
35
+
36
+ def __init__(self, component_name: str):
37
+ super().__init__(
38
+ f"Component with name '{component_name}' not found in the DSL Application."
39
+ )
40
+
41
+
42
+ class ReferenceNotFoundError(QTypeValidationError):
43
+ """Raised when a reference is not found in the lookup map."""
44
+
45
+ def __init__(
46
+ self,
47
+ reference: str,
48
+ type_hint: str | None = None,
49
+ available_refs: list[str] | None = None,
50
+ ):
51
+ if type_hint:
52
+ msg = (
53
+ f"Reference '{reference}' not found for type '{type_hint}'.\n"
54
+ )
55
+ else:
56
+ msg = f"Reference '{reference}' not found.\n"
57
+
58
+ # Add helpful suggestions if we have available references
59
+ if available_refs:
60
+ # Find similar names
61
+ similar = [
62
+ ref
63
+ for ref in available_refs
64
+ if reference.lower() in ref.lower()
65
+ or ref.lower() in reference.lower()
66
+ ]
67
+ if similar:
68
+ msg += f"Did you mean one of these? {', '.join(similar[:5])}"
69
+ elif len(available_refs) <= 10:
70
+ msg += f"Available references: {', '.join(available_refs)}"
71
+ else:
72
+ msg += (
73
+ f"There are {len(available_refs)} available "
74
+ "references. Check your spelling."
75
+ )
76
+
77
+ super().__init__(msg)
78
+
79
+
80
+ def _update_map_with_unique_check(
81
+ current_map: Dict[str, qtype.dsl.domain_types.StrictBaseModel],
82
+ new_objects: list[qtype.dsl.domain_types.StrictBaseModel],
83
+ ) -> None:
84
+ """
85
+ Update a map with new objects, ensuring unique IDs.
86
+
87
+ Args:
88
+ current_map: The current map of objects by ID.
89
+ new_objects: List of new objects to add to the map.
90
+
91
+ Returns:
92
+ Updated map with new objects added, ensuring unique IDs.
93
+ """
94
+ for obj in new_objects:
95
+ if obj is None:
96
+ # If the object is None, we skip it.
97
+ continue
98
+ if isinstance(obj, str) or isinstance(obj, base_types.Reference):
99
+ # If the object is a string, we assume it is an ID and skip it.
100
+ # This is a special case where we do not want to add the string itself.
101
+ continue
102
+ # Note: There is no current abstraction for the `id` field, so we assume it exists.
103
+ obj_id = obj.id # type: ignore[attr-defined]
104
+ # If the object already exists in the map, we check if it is the same object.
105
+ # If it is not the same object, we raise an error.
106
+ # This ensures that we do not have duplicate components with the same ID.
107
+ if obj_id in current_map and id(current_map[obj_id]) != id(obj):
108
+ raise DuplicateComponentError(obj.id, obj, current_map[obj_id]) # type: ignore
109
+ else:
110
+ current_map[obj_id] = obj
111
+
112
+
113
+ def _collect_components_from_object(
114
+ obj: qtype.dsl.domain_types.StrictBaseModel,
115
+ ) -> list[qtype.dsl.domain_types.StrictBaseModel]:
116
+ """
117
+ Collect all components from an object that have IDs.
118
+ This includes the object itself and any nested components.
119
+
120
+ Args:
121
+ obj: The object to extract components from.
122
+
123
+ Returns:
124
+ List of components with IDs.
125
+ """
126
+ components = []
127
+
128
+ # Add the object itself if it has an ID
129
+ if hasattr(obj, "id"):
130
+ components.append(obj)
131
+
132
+ # For Flow, also collect embedded steps, inputs, and outputs
133
+ if isinstance(obj, dsl.Flow):
134
+ components.extend(obj.steps or []) # type: ignore
135
+ components.extend(obj.variables or []) # type: ignore
136
+
137
+ return components
138
+
139
+
140
+ def _update_maps_with_embedded_objects(
141
+ lookup_map: Dict[str, qtype.dsl.domain_types.StrictBaseModel],
142
+ embedded_objects: list[qtype.dsl.domain_types.StrictBaseModel],
143
+ ) -> None:
144
+ """
145
+ Update lookup maps with embedded objects.
146
+ Embedded objects are when the user specifies the object and not just the ID.
147
+
148
+ Args:
149
+ lookup_maps: The current lookup maps to update.
150
+ embedded_objects: List of embedded objects to add to the maps.
151
+ """
152
+ for obj in embedded_objects:
153
+ components = _collect_components_from_object(obj)
154
+ _update_map_with_unique_check(lookup_map, components)
155
+
156
+
157
+ def _build_lookup_maps(
158
+ document: Any,
159
+ lookup_map: Dict[str, qtype.dsl.domain_types.StrictBaseModel]
160
+ | None = None,
161
+ ) -> Dict[str, qtype.dsl.domain_types.StrictBaseModel]:
162
+ """
163
+ Build lookup map for all objects in a DSL Document.
164
+ This function creates a dictionary of id -> component, where each key is a
165
+ component id and the value is the component.
166
+
167
+ Works with any Document type (Application, Flow, *List types, etc.).
168
+
169
+ Args:
170
+ document: The DSL Document to build lookup maps for.
171
+ Can be Application, Flow, or any RootModel list type.
172
+
173
+ Returns:
174
+ Dict[str, dsl.StrictBaseModel]: A dictionary of lookup maps
175
+
176
+ Throws:
177
+ QTypeValidationError: If there are duplicate components with the same ID.
178
+ """
179
+ if lookup_map is None:
180
+ lookup_map = {}
181
+
182
+ # Handle Application specially since it has multiple component lists
183
+ if isinstance(document, dsl.Application):
184
+ component_names = {
185
+ f
186
+ for f in dsl.Application.model_fields.keys()
187
+ if f not in {"id", "references", "description"}
188
+ }
189
+
190
+ for component_name in component_names:
191
+ if not hasattr(document, component_name):
192
+ raise ComponentNotFoundError(component_name)
193
+ components = getattr(document, component_name) or []
194
+ if not isinstance(components, list):
195
+ components = [components] # Ensure we have a list
196
+ _update_map_with_unique_check(lookup_map, components)
197
+ _update_maps_with_embedded_objects(lookup_map, components)
198
+
199
+ # Handle references (which can contain nested Applications or other documents)
200
+ for ref in document.references or []:
201
+ ref = ref.root # type: ignore
202
+ _build_lookup_maps(ref, lookup_map)
203
+
204
+ lookup_map[document.id] = document
205
+
206
+ # Handle RootModel list types (e.g., AuthorizationProviderList, IndexList, etc.)
207
+ elif hasattr(document, "root") and isinstance(
208
+ getattr(document, "root"), list
209
+ ):
210
+ root_list = getattr(document, "root")
211
+ _update_map_with_unique_check(lookup_map, root_list)
212
+ _update_maps_with_embedded_objects(lookup_map, root_list)
213
+
214
+ # Handle single component documents (e.g., Flow, Agent, etc.)
215
+ else:
216
+ components = _collect_components_from_object(document)
217
+ _update_map_with_unique_check(lookup_map, components)
218
+
219
+ return lookup_map
220
+
221
+
222
+ def _resolve_reference(
223
+ ref: str, type_hint: Type, lookup_map: Dict[str, Any]
224
+ ) -> Any:
225
+ """
226
+ Resolve a single reference string to its object.
227
+
228
+ Args:
229
+ ref: The reference ID to resolve
230
+ type_hint: Type hint for better error messages
231
+ lookup_map: Map of component IDs to objects
232
+
233
+ Returns:
234
+ The resolved object
235
+
236
+ Raises:
237
+ ReferenceNotFoundError: If the reference cannot be found
238
+ """
239
+ resolved_obj = lookup_map.get(ref)
240
+ if resolved_obj is None:
241
+ available_refs = list(lookup_map.keys())
242
+ raise ReferenceNotFoundError(ref, str(type_hint), available_refs)
243
+ return resolved_obj
244
+
245
+
246
+ def _resolve_rootmodel_references(
247
+ model: RootModel, lookup_map: Dict[str, Any]
248
+ ) -> None:
249
+ """
250
+ Resolve references in a RootModel (list-based documents).
251
+
252
+ Args:
253
+ model: RootModel instance to resolve
254
+ lookup_map: Map of component IDs to objects
255
+ """
256
+ root_list = model.root # type: ignore
257
+ if not isinstance(root_list, list):
258
+ return
259
+
260
+ for i, item in enumerate(root_list):
261
+ match item:
262
+ case base_types.Reference():
263
+ root_list[i] = _resolve_reference(
264
+ item.ref, type(item), lookup_map
265
+ )
266
+ case BaseModel():
267
+ _resolve_all_references(item, lookup_map)
268
+
269
+
270
+ def _resolve_list_references(
271
+ field_value: list, lookup_map: Dict[str, Any]
272
+ ) -> None:
273
+ """
274
+ Resolve references within a list field.
275
+
276
+ Args:
277
+ field_value: List to process
278
+ lookup_map: Map of component IDs to objects
279
+ """
280
+ for i, item in enumerate(field_value):
281
+ match item:
282
+ case base_types.Reference():
283
+ field_value[i] = _resolve_reference(
284
+ item.ref, type(item), lookup_map
285
+ )
286
+ case BaseModel():
287
+ _resolve_all_references(item, lookup_map)
288
+
289
+
290
+ def _resolve_dict_references(
291
+ field_value: dict, lookup_map: Dict[str, Any]
292
+ ) -> None:
293
+ """
294
+ Resolve references within a dict field.
295
+
296
+ Args:
297
+ field_value: Dict to process
298
+ lookup_map: Map of component IDs to objects
299
+ """
300
+ for k, v in field_value.items():
301
+ match v:
302
+ case base_types.Reference():
303
+ field_value[k] = _resolve_reference(v.ref, type(v), lookup_map)
304
+ case BaseModel():
305
+ _resolve_all_references(v, lookup_map)
306
+
307
+
308
+ def _resolve_all_references(
309
+ model: BaseModel,
310
+ lookup_map: Dict[str, Any],
311
+ ) -> None:
312
+ """
313
+ Walk a Pydantic model tree and resolve all Reference objects.
314
+
315
+ Args:
316
+ model: The model to process
317
+ lookup_map: Map of component IDs to objects
318
+ """
319
+ # Check if this is a RootModel (list-based document like ModelList, ToolList, etc.)
320
+ if isinstance(model, RootModel):
321
+ _resolve_rootmodel_references(model, lookup_map)
322
+ return
323
+
324
+ # For regular BaseModel types, iterate over fields
325
+ for field_name, field_value in model.__iter__():
326
+ match field_value:
327
+ case base_types.Reference():
328
+ setattr(
329
+ model,
330
+ field_name,
331
+ _resolve_reference(
332
+ field_value.ref, type(field_value), lookup_map
333
+ ),
334
+ )
335
+ case BaseModel():
336
+ _resolve_all_references(field_value, lookup_map)
337
+ case list() if len(field_value) > 0:
338
+ _resolve_list_references(field_value, lookup_map)
339
+ case dict():
340
+ _resolve_dict_references(field_value, lookup_map)
341
+
342
+
343
+ def link(document: dsl.DocumentType) -> dsl.DocumentType:
344
+ """
345
+ Links (resolves) all ID references in a DSL Document to their actual objects.
346
+
347
+ Works with any DocumentType:
348
+ - Application: Full application with all components
349
+ - Flow: Individual flow definition
350
+ - Agent: Individual agent definition
351
+ - AuthorizationProviderList: List of authorization providers
352
+ - IndexList: List of indexes
353
+ - ModelList: List of models
354
+ - ToolList: List of tools
355
+ - TypeList: List of custom types
356
+ - VariableList: List of variables
357
+
358
+ IMPORTANT: The returned object breaks the type safety of the original.
359
+ All Reference[T] fields will be replaced with actual T objects, which
360
+ violates the original type signatures. This is intentional for the
361
+ linking phase before transformation to semantic IR.
362
+
363
+ Args:
364
+ document: Any valid DSL DocumentType (one of the 9 possible document structures).
365
+
366
+ Returns:
367
+ The same document with all internal references resolved to actual objects.
368
+
369
+ Raises:
370
+ DuplicateComponentError: If there are duplicate components with the same ID.
371
+ ReferenceNotFoundError: If a reference cannot be resolved.
372
+ ComponentNotFoundError: If an expected component is missing.
373
+ """
374
+
375
+ # First, make a lookup map of all objects in the document.
376
+ # This ensures that all object ids are unique.
377
+ lookup_map = _build_lookup_maps(document)
378
+
379
+ # Now we resolve all ID references in the document.
380
+ # All DocumentType variants are BaseModel instances (including RootModel-based *List types)
381
+ if isinstance(document, BaseModel):
382
+ _resolve_all_references(document, lookup_map)
383
+
384
+ return document # type: ignore[return-value]