@aws/nx-plugin 1.0.0-rc.98 → 1.0.1

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 (117) hide show
  1. package/LICENSE-THIRD-PARTY +11686 -23398
  2. package/README.md +18 -0
  3. package/generators.json +7 -0
  4. package/migrations.json +34 -1
  5. package/package.json +6 -6
  6. package/src/agentcore-gateway/schema.json +1 -0
  7. package/src/agentcore-harness/generator.d.ts +1 -1
  8. package/src/connection/scaffold-catalog.d.ts +4 -0
  9. package/src/connection/scaffold-catalog.js +3 -6
  10. package/src/connection/scaffold-catalog.js.map +1 -1
  11. package/src/infra/app/generator.d.ts +1 -1
  12. package/src/init/generator.d.ts +1 -1
  13. package/src/mcp-server/guide-pipeline.d.ts +2 -1
  14. package/src/mcp-server/guide-pipeline.js +6 -0
  15. package/src/mcp-server/guide-pipeline.js.map +1 -1
  16. package/src/mcp-server/mdx-ast.d.ts +7 -0
  17. package/src/mcp-server/mdx-ast.js +15 -0
  18. package/src/mcp-server/mdx-ast.js.map +1 -1
  19. package/src/mcp-server/schema-registry.d.ts +2 -2
  20. package/src/mcp-server/schema-registry.js +2 -2
  21. package/src/mcp-server/schema-registry.js.map +1 -1
  22. package/src/open-api/py-client/__snapshots__/generator.additional-properties.spec.ts.snap +34 -0
  23. package/src/open-api/py-client/__snapshots__/generator.arrays.spec.ts.snap +1750 -0
  24. package/src/open-api/py-client/__snapshots__/generator.complex-types.spec.ts.snap +82 -0
  25. package/src/open-api/py-client/__snapshots__/generator.composite-types.spec.ts.snap +447 -0
  26. package/src/open-api/py-client/__snapshots__/generator.duplicate-types.spec.ts.snap +404 -0
  27. package/src/open-api/py-client/__snapshots__/generator.errors.spec.ts.snap +430 -0
  28. package/src/open-api/py-client/__snapshots__/generator.fast-api.spec.ts.snap +447 -0
  29. package/src/open-api/py-client/__snapshots__/generator.petstore.spec.ts.snap +3488 -0
  30. package/src/open-api/py-client/__snapshots__/generator.primitive-types.spec.ts.snap +1444 -0
  31. package/src/open-api/py-client/__snapshots__/generator.request.spec.ts.snap +390 -0
  32. package/src/open-api/py-client/__snapshots__/generator.reserved-keywords.spec.ts.snap +364 -0
  33. package/src/open-api/py-client/__snapshots__/generator.response.spec.ts.snap +739 -0
  34. package/src/open-api/py-client/__snapshots__/generator.streaming.spec.ts.snap +384 -0
  35. package/src/open-api/py-client/__snapshots__/generator.tags.spec.ts.snap +414 -0
  36. package/src/open-api/py-client/files/client/__clientModuleName__.py.template +1076 -0
  37. package/src/open-api/py-client/files/shared/__init__.py.template +28 -0
  38. package/src/open-api/py-client/files/shared/errors.py.template +37 -0
  39. package/src/open-api/py-client/files/shared/types.py.template +319 -0
  40. package/src/open-api/py-client/generator.d.ts +53 -0
  41. package/src/open-api/py-client/generator.js +119 -0
  42. package/src/open-api/py-client/generator.js.map +1 -0
  43. package/src/open-api/py-client/schema.d.js +6 -0
  44. package/src/open-api/py-client/schema.d.js.map +1 -0
  45. package/src/open-api/py-client/schema.d.ts +12 -0
  46. package/src/open-api/py-client/schema.json +28 -0
  47. package/src/open-api/py-client/vessel-registry-spec.json +2716 -0
  48. package/src/open-api/ts-client/__snapshots__/generator.edge-cases.spec.ts.snap +274 -0
  49. package/src/open-api/ts-client/petstore-spec.d.ts +6 -0
  50. package/src/open-api/ts-client/petstore-spec.js +1275 -0
  51. package/src/open-api/ts-client/petstore-spec.js.map +1 -0
  52. package/src/open-api/ts-hooks/generator.spec.tsx +1 -1
  53. package/src/open-api/utils/codegen-data/languages.d.ts +68 -2
  54. package/src/open-api/utils/codegen-data/languages.js +433 -21
  55. package/src/open-api/utils/codegen-data/languages.js.map +1 -1
  56. package/src/open-api/utils/codegen-data/types.d.ts +187 -0
  57. package/src/open-api/utils/codegen-data/types.js +10 -1
  58. package/src/open-api/utils/codegen-data/types.js.map +1 -1
  59. package/src/open-api/utils/codegen-data.d.ts +40 -1
  60. package/src/open-api/utils/codegen-data.js +622 -17
  61. package/src/open-api/utils/codegen-data.js.map +1 -1
  62. package/src/open-api/utils/normalise.js +175 -41
  63. package/src/open-api/utils/normalise.js.map +1 -1
  64. package/src/open-api/utils/parser.js +1 -1
  65. package/src/open-api/utils/parser.js.map +1 -1
  66. package/src/preset/__snapshots__/generator.spec.ts.snap +3 -3
  67. package/src/preset/generator.d.ts +1 -1
  68. package/src/py/agent/gateway-connection/generator.js +0 -3
  69. package/src/py/agent/gateway-connection/generator.js.map +1 -1
  70. package/src/py/agent/react-connection/generator.d.ts +1 -1
  71. package/src/py/agent/schema.json +2 -0
  72. package/src/py/fast-api/react/generator.d.ts +1 -1
  73. package/src/py/mcp-server/schema.json +1 -0
  74. package/src/sdk/open-api.d.ts +2 -0
  75. package/src/sdk/open-api.js +1 -0
  76. package/src/sdk/open-api.js.map +1 -1
  77. package/src/smithy/project/generator.d.ts +1 -1
  78. package/src/smithy/react-connection/generator.d.ts +1 -1
  79. package/src/terraform/project/generator.d.ts +1 -1
  80. package/src/trpc/react/generator.d.ts +1 -1
  81. package/src/ts/agent/a2a-connection/generator.d.ts +1 -1
  82. package/src/ts/agent/gateway-connection/generator.d.ts +1 -1
  83. package/src/ts/agent/gateway-connection/generator.js +0 -3
  84. package/src/ts/agent/gateway-connection/generator.js.map +1 -1
  85. package/src/ts/agent/mcp-connection/generator.d.ts +1 -1
  86. package/src/ts/agent/react-connection/generator.d.ts +1 -1
  87. package/src/ts/agent/schema.json +1 -0
  88. package/src/ts/api/schema.json +2 -0
  89. package/src/ts/astro-docs/generator.d.ts +1 -1
  90. package/src/ts/dcr-proxy/generator.d.ts +1 -1
  91. package/src/ts/dynamodb/generator.d.ts +1 -1
  92. package/src/ts/lambda-function/generator.d.ts +1 -1
  93. package/src/ts/lib/generator.d.ts +1 -1
  94. package/src/ts/mcp-server/schema.json +1 -0
  95. package/src/ts/nx-generator/__snapshots__/generator.spec.ts.snap +1 -1
  96. package/src/ts/nx-generator/files/nx-plugin-for-aws/generator/generator.spec.ts.template +1 -1
  97. package/src/ts/nx-generator/generator.d.ts +1 -1
  98. package/src/ts/nx-migration/generator.d.ts +1 -1
  99. package/src/ts/nx-plugin/generator.d.ts +1 -1
  100. package/src/ts/rdb/generator.d.ts +1 -1
  101. package/src/ts/react-website/agui/generator.d.ts +1 -1
  102. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +10 -10
  103. package/src/ts/react-website/app/schema.json +1 -0
  104. package/src/ts/website/app/schema.json +1 -0
  105. package/src/utils/metrics-assertions.d.ts +18 -0
  106. package/src/utils/metrics-assertions.js +42 -0
  107. package/src/utils/metrics-assertions.js.map +1 -0
  108. package/src/utils/test/python-dependencies.d.ts +8 -0
  109. package/src/utils/test/python-dependencies.js +14 -0
  110. package/src/utils/test/python-dependencies.js.map +1 -0
  111. package/src/utils/test/python-worker/worker.py +703 -0
  112. package/src/utils/test/warm-python-cache.d.ts +18 -0
  113. package/src/utils/test/warm-python-cache.js +46 -0
  114. package/src/utils/test/warm-python-cache.js.map +1 -0
  115. package/src/utils/versions.d.ts +10 -9
  116. package/src/utils/versions.js +9 -8
  117. package/src/utils/versions.js.map +1 -1
@@ -0,0 +1,447 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`openApiPyClientGenerator - fast-api-shaped specs > round-trips a FastAPI-shaped echo endpoint > client.py 1`] = `
4
+ """"DemoApi — AUTO-GENERATED synchronous client."""
5
+
6
+ from __future__ import annotations
7
+
8
+ import datetime
9
+ from collections.abc import Iterator
10
+ from dataclasses import dataclass, field
11
+ from typing import Any, TypeVar
12
+ from urllib.parse import quote
13
+
14
+ import httpx
15
+ from pydantic import BaseModel, ValidationError
16
+
17
+ from . import types
18
+ from .errors import (
19
+ ApiError as ApiError,
20
+ )
21
+ from .errors import (
22
+ EchoApiError as EchoApiError,
23
+ )
24
+ from .errors import (
25
+ StreamChunksApiError as StreamChunksApiError,
26
+ )
27
+
28
+ _ErrorT = TypeVar("_ErrorT", bound=BaseModel)
29
+
30
+
31
+ @dataclass
32
+ class DemoApiConfig:
33
+ """Client configuration for DemoApi."""
34
+
35
+ #: Base URL for the API.
36
+ url: str
37
+ #: Client used for every request. Supply your own to add authentication or
38
+ #: any other middleware — an \`\`httpx.Auth\`\` (e.g. a SigV4 signer), an event
39
+ #: hook, a custom transport, timeouts, retries or a proxy all apply, and the
40
+ #: client's own headers and query params are sent alongside each operation's.
41
+ #: A supplied client is never closed by this one, so it can be shared.
42
+ httpx_client: httpx.Client | None = None
43
+ #: Headers added to every request, where the operation sets none itself.
44
+ headers: dict[str, str] = field(default_factory=dict)
45
+ #: By default the client sends a Content-Type header set to the media type
46
+ #: the OpenAPI specification declares for the request. Set this to omit it.
47
+ omit_content_type_header: bool = False
48
+
49
+
50
+ class DemoApi:
51
+ """Synchronous API client for DemoApi."""
52
+
53
+ def __init__(self, config: DemoApiConfig) -> None:
54
+ self._config = config
55
+ self._client = config.httpx_client or httpx.Client()
56
+ self._owns_client = config.httpx_client is None
57
+ self._base_url = config.url.rstrip("/")
58
+
59
+ def __enter__(self) -> DemoApi:
60
+ return self
61
+
62
+ def __exit__(self, *exc: Any) -> None:
63
+ self.close()
64
+
65
+ def close(self) -> None:
66
+ if self._owns_client:
67
+ self._client.close()
68
+
69
+ def _url(
70
+ self,
71
+ path: str,
72
+ path_params: dict[str, Any],
73
+ path_styles: dict[str, tuple[str, bool]] | None = None,
74
+ ) -> str:
75
+ for key, value in path_params.items():
76
+ style, explode = (path_styles or {}).get(key, ("simple", False))
77
+ # An object expands to its key,value members; a list to its items.
78
+ # Each is encoded on its own so the separators between them stay
79
+ # literal, as RFC 6570 requires.
80
+ dumped = self._dump(value)
81
+ if isinstance(dumped, dict):
82
+ values = [
83
+ part
84
+ for k, v in dumped.items()
85
+ if v is not None
86
+ for part in (k, self._scalar(v))
87
+ ]
88
+ elif isinstance(dumped, list):
89
+ values = list(dumped)
90
+ else:
91
+ values = [value]
92
+ if style == "matrix":
93
+ # RFC 6570 path-style expansion: ;key=a,b (explode: ;key=a;key=b)
94
+ if explode:
95
+ rendered = "".join(
96
+ ";" + key + "=" + quote(self._scalar(v), safe="")
97
+ for v in values
98
+ )
99
+ else:
100
+ rendered = (
101
+ ";"
102
+ + key
103
+ + "="
104
+ + ",".join(quote(self._scalar(v), safe="") for v in values)
105
+ )
106
+ elif style == "label":
107
+ # RFC 6570 label expansion: .a,b (explode: .a.b)
108
+ rendered = "." + ("." if explode else ",").join(
109
+ quote(self._scalar(v), safe="") for v in values
110
+ )
111
+ else:
112
+ # RFC 6570 simple expansion: a list renders comma-separated.
113
+ rendered = ",".join(quote(self._scalar(v), safe="") for v in values)
114
+ path = path.replace("{" + key + "}", rendered)
115
+ return self._base_url + path
116
+
117
+ def _deep_object(self, key: str, value: Any, out: dict[str, Any]) -> None:
118
+ if isinstance(value, BaseModel):
119
+ value = value.model_dump(mode="json", by_alias=True, exclude_unset=True)
120
+ if isinstance(value, dict):
121
+ for prop, v in value.items():
122
+ self._deep_object(f"{key}[{prop}]", v, out)
123
+ elif value is not None:
124
+ out[key] = value
125
+
126
+ _COLLECTION_DELIMITERS = {"csv": ",", "ssv": " ", "pipes": "|"}
127
+
128
+ #: Characters left literal in a cookie value: every RFC 6265 cookie-octet
129
+ #: except the \`,\` and \`;\` this client joins members on. A \`=\` stays literal
130
+ #: too — only the first one separates a cookie's name from its value.
131
+ _COOKIE_SAFE = "!#$%&'()*+-./:<>?@[]^_\`{|}~="
132
+
133
+ def _scalar(self, value: Any) -> str:
134
+ # The wire form of a single parameter value: JSON spellings for bools,
135
+ # ISO-8601 for dates, and the model's own wire shape for anything else.
136
+ if isinstance(value, bool):
137
+ return "true" if value else "false"
138
+ if isinstance(value, (datetime.date, datetime.datetime)):
139
+ return value.isoformat()
140
+ dumped = self._dump(value)
141
+ if isinstance(dumped, str):
142
+ return dumped
143
+ # RFC 6570 renders a list as its comma-joined members and an object as
144
+ # comma-joined key,value pairs. Python's own \`str\` would emit a repr —
145
+ # \`['a', 'b']\`, quotes and spaces included.
146
+ if isinstance(dumped, list):
147
+ return ",".join(self._scalar(v) for v in dumped)
148
+ if isinstance(dumped, dict):
149
+ return ",".join(
150
+ f"{k},{self._scalar(v)}" for k, v in dumped.items() if v is not None
151
+ )
152
+ if dumped is None:
153
+ return ""
154
+ return str(dumped)
155
+
156
+ def _query(
157
+ self,
158
+ query_params: dict[str, Any],
159
+ collection_formats: dict[str, str] | None = None,
160
+ ) -> dict[str, Any]:
161
+ out: dict[str, Any] = {}
162
+ for key, value in query_params.items():
163
+ if value is None:
164
+ continue
165
+ fmt = (collection_formats or {}).get(key)
166
+ if fmt == "deepObject":
167
+ self._deep_object(key, value, out)
168
+ elif isinstance(value, list):
169
+ delimiter = self._COLLECTION_DELIMITERS.get(fmt or "multi")
170
+ if delimiter is None:
171
+ out[key] = [self._scalar(v) for v in value]
172
+ else:
173
+ out[key] = delimiter.join(self._scalar(v) for v in value)
174
+ elif self._is_object(value):
175
+ # OpenAPI's default query style is form/explode, under which an
176
+ # object expands to one parameter per property rather than
177
+ # being stringified.
178
+ for prop, prop_value in self._as_dict(value).items():
179
+ if prop_value is not None:
180
+ out[prop] = self._scalar(prop_value)
181
+ else:
182
+ out[key] = self._scalar(value)
183
+ return out
184
+
185
+ def _is_object(self, value: Any) -> bool:
186
+ return isinstance(value, (dict, BaseModel))
187
+
188
+ def _as_dict(self, value: Any) -> dict[str, Any]:
189
+ if isinstance(value, BaseModel):
190
+ return value.model_dump(mode="json", by_alias=True, exclude_unset=True)
191
+ return dict(value)
192
+
193
+ def _headers(
194
+ self,
195
+ header_params: dict[str, Any] | None = None,
196
+ collection_formats: dict[str, str] | None = None,
197
+ cookie_params: dict[str, Any] | None = None,
198
+ ) -> list[tuple[str, str]]:
199
+ out: list[tuple[str, str]] = []
200
+ for key, value in (header_params or {}).items():
201
+ if value is None:
202
+ continue
203
+ if isinstance(value, list):
204
+ fmt = (collection_formats or {}).get(key, "csv")
205
+ delimiter = self._COLLECTION_DELIMITERS.get(fmt)
206
+ if delimiter is None:
207
+ for item in value:
208
+ out.append((key, self._scalar(item)))
209
+ else:
210
+ out.append((key, delimiter.join(self._scalar(v) for v in value)))
211
+ else:
212
+ out.append((key, self._scalar(value)))
213
+ # A config header only applies where the operation didn't set one:
214
+ # httpx comma-joins repeated names, which would corrupt the value.
215
+ operation_headers = {key.lower() for key, _ in out}
216
+ out.extend(
217
+ (key, value)
218
+ for key, value in self._config.headers.items()
219
+ if key.lower() not in operation_headers
220
+ )
221
+ # The operation's cookies are merged into one \`Cookie\` header alongside
222
+ # every other source. Passing them to httpx's \`cookies=\` instead would
223
+ # drop them outright whenever a \`Cookie\` header is present, since
224
+ # http.cookiejar skips a request that already carries one — and setting
225
+ # the header here would in turn shadow the caller's own jar and header,
226
+ # which httpx resolves in favour of the more specific value.
227
+ cookies = self._cookies(cookie_params or {})
228
+ if cookies:
229
+ pairs = [
230
+ *(
231
+ value
232
+ for source in (self._client.headers, dict(out))
233
+ for key, value in source.items()
234
+ if key.lower() == "cookie"
235
+ ),
236
+ *(f"{key}={value}" for key, value in self._client.cookies.items()),
237
+ *(f"{key}={value}" for key, value in cookies.items()),
238
+ ]
239
+ out = [(key, value) for key, value in out if key.lower() != "cookie"]
240
+ out.append(("Cookie", "; ".join(pairs)))
241
+ return out
242
+
243
+ def _default_content_type(
244
+ self, header_params: dict[str, Any], media_type: str
245
+ ) -> None:
246
+ # The media type the specification declares, applied unless the operation
247
+ # takes a Content-Type of its own and the caller supplied one. Header
248
+ # names are case-insensitive, and a declared header the caller omitted is
249
+ # present holding \`None\` — neither counts as the caller setting it.
250
+ if any(
251
+ key.lower() == "content-type" and value is not None
252
+ for key, value in header_params.items()
253
+ ):
254
+ return
255
+ for key in list(header_params):
256
+ if key.lower() == "content-type":
257
+ header_params[key] = media_type
258
+ return
259
+ header_params["Content-Type"] = media_type
260
+
261
+ def _cookies(self, cookie_params: dict[str, Any]) -> dict[str, str]:
262
+ out: dict[str, str] = {}
263
+ for key, value in cookie_params.items():
264
+ if value is None:
265
+ continue
266
+ dumped = self._dump(value)
267
+ # A cookie uses form-style expansion, so a list joins on \`,\` and an
268
+ # object on \`,\` between each key and value. Members are encoded so a
269
+ # \`;\` or \`,\` inside one can't be read as a delimiter, while the
270
+ # joining commas stay literal.
271
+ if isinstance(dumped, list):
272
+ rendered = ",".join(self._cookie_value(v) for v in dumped)
273
+ elif isinstance(dumped, dict):
274
+ rendered = ",".join(
275
+ self._cookie_value(k) + "," + self._cookie_value(v)
276
+ for k, v in dumped.items()
277
+ if v is not None
278
+ )
279
+ else:
280
+ rendered = self._cookie_value(value)
281
+ out[key] = rendered
282
+ return out
283
+
284
+ def _cookie_value(self, value: Any) -> str:
285
+ # Only the characters a cookie parser treats as structure are escaped, so
286
+ # a timestamp keeps its colons and a base64 token its \`=\` padding. Servers
287
+ # do not URL-decode cookies, so anything escaped here arrives escaped.
288
+ return quote(self._scalar(value), safe=self._COOKIE_SAFE)
289
+
290
+ def _dump(self, value: Any) -> Any:
291
+ if value is None:
292
+ return None
293
+ if isinstance(value, BaseModel):
294
+ return value.model_dump(mode="json", by_alias=True, exclude_unset=True)
295
+ if isinstance(value, (list, tuple)):
296
+ return [self._dump(v) for v in value]
297
+ if isinstance(value, dict):
298
+ return {k: self._dump(v) for k, v in value.items()}
299
+ if isinstance(value, (datetime.date, datetime.datetime)):
300
+ return value.isoformat()
301
+ return value
302
+
303
+ def _error_payload(self, response: httpx.Response) -> Any:
304
+ # An error body is whatever the server actually sent, which need not be
305
+ # the JSON the spec declares (a proxy's HTML page, say).
306
+ try:
307
+ return response.json()
308
+ except ValueError:
309
+ return response.text
310
+
311
+ def _error(self, wrapper: type[_ErrorT], status: int, payload: Any) -> _ErrorT:
312
+ # Coerce to the declared error type, falling back to the raw payload so
313
+ # a body that doesn't match the spec still raises the typed exception.
314
+ try:
315
+ return wrapper.model_validate({"status": status, "error": payload})
316
+ except ValidationError:
317
+ return wrapper.model_construct(status=status, error=payload)
318
+
319
+ def echo(
320
+ self,
321
+ *,
322
+ message: str,
323
+ ) -> types.EchoOutput:
324
+ query_params: dict[str, Any] = {"message": message}
325
+ query_formats: dict[str, str] | None = {"message": "multi"}
326
+ request_kwargs: dict[str, Any] = {}
327
+ _request_url = self._url("/echo", {})
328
+ response = self._client.request(
329
+ "GET",
330
+ _request_url,
331
+ params=self._query(query_params, query_formats),
332
+ headers=self._headers(),
333
+ **request_kwargs,
334
+ )
335
+ if response.status_code == 200:
336
+ return types.EchoOutput.model_validate(response.json())
337
+ if response.status_code == 500:
338
+ raise EchoApiError(
339
+ response.status_code,
340
+ self._error(types.Echo500Error, 500, self._error_payload(response)),
341
+ )
342
+ raise EchoApiError(response.status_code, None)
343
+
344
+ def stream_chunks(
345
+ self,
346
+ *,
347
+ prompt: str,
348
+ count: int | None = None,
349
+ ) -> Iterator[types.Chunk]:
350
+ query_params: dict[str, Any] = {"prompt": prompt, "count": count}
351
+ query_formats: dict[str, str] | None = {"prompt": "multi", "count": "multi"}
352
+ request_kwargs: dict[str, Any] = {}
353
+ _request_url = self._url("/stream", {})
354
+ with self._client.stream(
355
+ "POST",
356
+ _request_url,
357
+ params=self._query(query_params, query_formats),
358
+ headers=self._headers(),
359
+ **request_kwargs,
360
+ ) as response:
361
+ if response.status_code == 200:
362
+ buffer = ""
363
+ for chunk in response.iter_text():
364
+ buffer += chunk
365
+ while "\\n" in buffer:
366
+ line, buffer = buffer.split("\\n", 1)
367
+ # \`iter_text\` doesn't translate newlines, so a CRLF
368
+ # stream leaves a trailing carriage return on each line.
369
+ line = line.rstrip("\\r")
370
+ if line.strip():
371
+ yield types.Chunk.model_validate_json(line)
372
+ if buffer.strip():
373
+ yield types.Chunk.model_validate_json(buffer)
374
+ return
375
+ response.read()
376
+ raise StreamChunksApiError(response.status_code, None)
377
+ "
378
+ `;
379
+
380
+ exports[`openApiPyClientGenerator - fast-api-shaped specs > round-trips a FastAPI-shaped echo endpoint > types.py 1`] = `
381
+ """"Types for DemoApi — AUTO-GENERATED, do not edit."""
382
+
383
+ from __future__ import annotations
384
+
385
+ from typing import Literal, Never, TypedDict
386
+
387
+ from pydantic import BaseModel, ConfigDict
388
+
389
+
390
+ class Chunk(BaseModel):
391
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
392
+
393
+ index: int
394
+ message: str
395
+
396
+
397
+ class EchoOutput(BaseModel):
398
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
399
+
400
+ message: str
401
+
402
+
403
+ class EchoRequestQueryParameters(BaseModel):
404
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
405
+
406
+ message: str
407
+
408
+
409
+ class InternalServerErrorDetails(BaseModel):
410
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
411
+
412
+ detail: str
413
+
414
+
415
+ class StreamChunksRequestQueryParameters(BaseModel):
416
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
417
+
418
+ prompt: str
419
+ count: int | None = None
420
+
421
+
422
+ class EchoRequest(TypedDict):
423
+ message: str
424
+
425
+
426
+ class StreamChunksRequestRequired(TypedDict):
427
+ prompt: str
428
+
429
+
430
+ class StreamChunksRequest(StreamChunksRequestRequired, total=False):
431
+ count: int
432
+
433
+
434
+ class Echo500Error(BaseModel):
435
+ """Error wrapper for Echo status 500."""
436
+
437
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
438
+
439
+ status: Literal[500]
440
+ error: InternalServerErrorDetails
441
+
442
+
443
+ EchoError = Echo500Error
444
+
445
+ StreamChunksError = Never
446
+ "
447
+ `;