microsoft-agents-hosting-fastapi 0.9.0.dev2__tar.gz → 0.9.0.dev4__tar.gz

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 (26) hide show
  1. {microsoft_agents_hosting_fastapi-0.9.0.dev2/microsoft_agents_hosting_fastapi.egg-info → microsoft_agents_hosting_fastapi-0.9.0.dev4}/PKG-INFO +2 -2
  2. microsoft_agents_hosting_fastapi-0.9.0.dev4/VERSION.txt +1 -0
  3. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/microsoft_agents/hosting/fastapi/jwt_authorization_middleware.py +1 -1
  4. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4/microsoft_agents_hosting_fastapi.egg-info}/PKG-INFO +2 -2
  5. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/microsoft_agents_hosting_fastapi.egg-info/SOURCES.txt +0 -5
  6. microsoft_agents_hosting_fastapi-0.9.0.dev4/microsoft_agents_hosting_fastapi.egg-info/requires.txt +2 -0
  7. microsoft_agents_hosting_fastapi-0.9.0.dev2/VERSION.txt +0 -1
  8. microsoft_agents_hosting_fastapi-0.9.0.dev2/microsoft_agents/hosting/fastapi/app/__init__.py +0 -14
  9. microsoft_agents_hosting_fastapi-0.9.0.dev2/microsoft_agents/hosting/fastapi/app/streaming/__init__.py +0 -12
  10. microsoft_agents_hosting_fastapi-0.9.0.dev2/microsoft_agents/hosting/fastapi/app/streaming/citation.py +0 -22
  11. microsoft_agents_hosting_fastapi-0.9.0.dev2/microsoft_agents/hosting/fastapi/app/streaming/citation_util.py +0 -85
  12. microsoft_agents_hosting_fastapi-0.9.0.dev2/microsoft_agents/hosting/fastapi/app/streaming/streaming_response.py +0 -392
  13. microsoft_agents_hosting_fastapi-0.9.0.dev2/microsoft_agents_hosting_fastapi.egg-info/requires.txt +0 -2
  14. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/LICENSE +0 -0
  15. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/MANIFEST.in +0 -0
  16. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/microsoft_agents/hosting/fastapi/__init__.py +0 -0
  17. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/microsoft_agents/hosting/fastapi/_start_agent_process.py +0 -0
  18. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/microsoft_agents/hosting/fastapi/agent_http_adapter.py +0 -0
  19. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/microsoft_agents/hosting/fastapi/channel_service_route_table.py +0 -0
  20. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/microsoft_agents/hosting/fastapi/cloud_adapter.py +0 -0
  21. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/microsoft_agents_hosting_fastapi.egg-info/dependency_links.txt +0 -0
  22. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/microsoft_agents_hosting_fastapi.egg-info/top_level.txt +0 -0
  23. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/pyproject.toml +0 -0
  24. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/readme.md +0 -0
  25. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/setup.cfg +0 -0
  26. {microsoft_agents_hosting_fastapi-0.9.0.dev2 → microsoft_agents_hosting_fastapi-0.9.0.dev4}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microsoft-agents-hosting-fastapi
3
- Version: 0.9.0.dev2
3
+ Version: 0.9.0.dev4
4
4
  Summary: Integration library for Microsoft Agents with FastAPI
5
5
  Author: Microsoft Corporation
6
6
  License-Expression: MIT
@@ -10,7 +10,7 @@ Classifier: Operating System :: OS Independent
10
10
  Requires-Python: >=3.10
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
- Requires-Dist: microsoft-agents-hosting-core==0.9.0.dev2
13
+ Requires-Dist: microsoft-agents-hosting-core==0.9.0.dev4
14
14
  Requires-Dist: fastapi>=0.104.0
15
15
  Dynamic: license-file
16
16
  Dynamic: requires-dist
@@ -0,0 +1 @@
1
+ 0.9.0.dev4
@@ -61,7 +61,7 @@ class JwtAuthorizationMiddleware:
61
61
  await response(scope, receive, send)
62
62
  return
63
63
  else:
64
- if not auth_config or not auth_config.CLIENT_ID:
64
+ if auth_config.ANONYMOUS_ALLOWED:
65
65
  request.state.claims_identity = token_validator.get_anonymous_claims()
66
66
  else:
67
67
  response = JSONResponse(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microsoft-agents-hosting-fastapi
3
- Version: 0.9.0.dev2
3
+ Version: 0.9.0.dev4
4
4
  Summary: Integration library for Microsoft Agents with FastAPI
5
5
  Author: Microsoft Corporation
6
6
  License-Expression: MIT
@@ -10,7 +10,7 @@ Classifier: Operating System :: OS Independent
10
10
  Requires-Python: >=3.10
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
- Requires-Dist: microsoft-agents-hosting-core==0.9.0.dev2
13
+ Requires-Dist: microsoft-agents-hosting-core==0.9.0.dev4
14
14
  Requires-Dist: fastapi>=0.104.0
15
15
  Dynamic: license-file
16
16
  Dynamic: requires-dist
@@ -10,11 +10,6 @@ microsoft_agents/hosting/fastapi/agent_http_adapter.py
10
10
  microsoft_agents/hosting/fastapi/channel_service_route_table.py
11
11
  microsoft_agents/hosting/fastapi/cloud_adapter.py
12
12
  microsoft_agents/hosting/fastapi/jwt_authorization_middleware.py
13
- microsoft_agents/hosting/fastapi/app/__init__.py
14
- microsoft_agents/hosting/fastapi/app/streaming/__init__.py
15
- microsoft_agents/hosting/fastapi/app/streaming/citation.py
16
- microsoft_agents/hosting/fastapi/app/streaming/citation_util.py
17
- microsoft_agents/hosting/fastapi/app/streaming/streaming_response.py
18
13
  microsoft_agents_hosting_fastapi.egg-info/PKG-INFO
19
14
  microsoft_agents_hosting_fastapi.egg-info/SOURCES.txt
20
15
  microsoft_agents_hosting_fastapi.egg-info/dependency_links.txt
@@ -0,0 +1,2 @@
1
+ microsoft-agents-hosting-core==0.9.0.dev4
2
+ fastapi>=0.104.0
@@ -1 +0,0 @@
1
- 0.9.0.dev2
@@ -1,14 +0,0 @@
1
- # Copyright (c) Microsoft Corporation. All rights reserved.
2
- # Licensed under the MIT License.
3
-
4
- from .streaming import (
5
- Citation,
6
- CitationUtil,
7
- StreamingResponse,
8
- )
9
-
10
- __all__ = [
11
- "Citation",
12
- "CitationUtil",
13
- "StreamingResponse",
14
- ]
@@ -1,12 +0,0 @@
1
- # Copyright (c) Microsoft Corporation. All rights reserved.
2
- # Licensed under the MIT License.
3
-
4
- from .citation import Citation
5
- from .citation_util import CitationUtil
6
- from .streaming_response import StreamingResponse
7
-
8
- __all__ = [
9
- "Citation",
10
- "CitationUtil",
11
- "StreamingResponse",
12
- ]
@@ -1,22 +0,0 @@
1
- # Copyright (c) Microsoft Corporation. All rights reserved.
2
- # Licensed under the MIT License.
3
-
4
- from typing import Optional
5
- from dataclasses import dataclass
6
-
7
-
8
- @dataclass
9
- class Citation:
10
- """Citations returned by the model."""
11
-
12
- content: str
13
- """The content of the citation."""
14
-
15
- title: Optional[str] = None
16
- """The title of the citation."""
17
-
18
- url: Optional[str] = None
19
- """The URL of the citation."""
20
-
21
- filepath: Optional[str] = None
22
- """The filepath of the document."""
@@ -1,85 +0,0 @@
1
- # Copyright (c) Microsoft Corporation. All rights reserved.
2
- # Licensed under the MIT License.
3
-
4
- import re
5
- from typing import List, Optional
6
-
7
- from microsoft_agents.activity import ClientCitation
8
-
9
-
10
- class CitationUtil:
11
- """Utility functions for manipulating text and citations."""
12
-
13
- @staticmethod
14
- def snippet(text: str, max_length: int) -> str:
15
- """
16
- Clips the text to a maximum length in case it exceeds the limit.
17
-
18
- Args:
19
- text: The text to clip.
20
- max_length: The maximum length of the text to return, cutting off the last whole word.
21
-
22
- Returns:
23
- The modified text
24
- """
25
- if len(text) <= max_length:
26
- return text
27
-
28
- snippet = text[:max_length]
29
- snippet = snippet[: min(len(snippet), snippet.rfind(" "))]
30
- snippet += "..."
31
- return snippet
32
-
33
- @staticmethod
34
- def format_citations_response(text: str) -> str:
35
- """
36
- Convert citation tags `[doc(s)n]` to `[n]` where n is a number.
37
-
38
- Args:
39
- text: The text to format.
40
-
41
- Returns:
42
- The formatted text.
43
- """
44
- return re.sub(r"\[docs?(\d+)\]", r"[\1]", text, flags=re.IGNORECASE)
45
-
46
- @staticmethod
47
- def get_used_citations(
48
- text: str, citations: List[ClientCitation]
49
- ) -> Optional[List[ClientCitation]]:
50
- """
51
- Get the citations used in the text. This will remove any citations that are
52
- included in the citations array from the response but not referenced in the text.
53
-
54
- Args:
55
- text: The text to search for citation references, i.e. [1], [2], etc.
56
- citations: The list of citations to search for.
57
-
58
- Returns:
59
- The list of citations used in the text.
60
- """
61
- regex = re.compile(r"\[(\d+)\]", re.IGNORECASE)
62
- matches = regex.findall(text)
63
-
64
- if not matches:
65
- return None
66
-
67
- # Remove duplicates
68
- filtered_matches = set(matches)
69
-
70
- # Add citations
71
- used_citations = []
72
- for match in filtered_matches:
73
- citation_ref = f"[{match}]"
74
- found = next(
75
- (
76
- citation
77
- for citation in citations
78
- if f"[{citation.position}]" == citation_ref
79
- ),
80
- None,
81
- )
82
- if found:
83
- used_citations.append(found)
84
-
85
- return used_citations if used_citations else None
@@ -1,392 +0,0 @@
1
- # Copyright (c) Microsoft Corporation. All rights reserved.
2
- # Licensed under the MIT License.
3
-
4
- import asyncio
5
- import logging
6
- from typing import List, Optional, Callable, Literal, TYPE_CHECKING
7
- from dataclasses import dataclass
8
-
9
- from microsoft_agents.activity import (
10
- Activity,
11
- Entity,
12
- Attachment,
13
- Channels,
14
- ClientCitation,
15
- DeliveryModes,
16
- SensitivityUsageInfo,
17
- )
18
-
19
- from microsoft_agents.hosting.core import error_resources
20
- from microsoft_agents.hosting.core.turn_context import TurnContext
21
-
22
- from .citation import Citation
23
- from .citation_util import CitationUtil
24
-
25
- logger = logging.getLogger(__name__)
26
-
27
-
28
- class StreamingResponse:
29
- """
30
- A helper class for streaming responses to the client.
31
-
32
- This class is used to send a series of updates to the client in a single response.
33
- The expected sequence of calls is:
34
-
35
- `queue_informative_update()`, `queue_text_chunk()`, `queue_text_chunk()`, ..., `end_stream()`.
36
-
37
- Once `end_stream()` is called, the stream is considered ended and no further updates can be sent.
38
- """
39
-
40
- def __init__(self, context: "TurnContext"):
41
- """
42
- Creates a new StreamingResponse instance.
43
-
44
- Args:
45
- context: Context for the current turn of conversation with the user.
46
- """
47
- self._context = context
48
- self._sequence_number = 1
49
- self._stream_id: Optional[str] = None
50
- self._message = ""
51
- self._queue: List[Callable[[], Activity]] = []
52
- self._queue_sync: Optional[asyncio.Task] = None
53
- self._chunk_queued = False
54
- self._ended = False
55
- self._cancelled = False
56
- self._is_streaming_channel = False
57
- self._interval = 0.1
58
- self._channel_id: Optional[str] = None
59
- self._attachments: Optional[List[Attachment]] = None
60
- self._citations: Optional[List[ClientCitation]] = None
61
- self._sensitivity_label: Optional[SensitivityUsageInfo] = None
62
- self._enable_feedback_loop = False
63
- self._feedback_loop_type: Optional[Literal["default", "custom"]] = None
64
- self._enable_generated_by_ai_label = False
65
-
66
- # Set defaults based on channel
67
- self._set_defaults(context)
68
-
69
- def queue_informative_update(self, text: str) -> None:
70
- """
71
- Queues an informative update to be sent to the client.
72
-
73
- Informative updates do not contain the message content that the user will
74
- read but rather an indication that the agent is processing the request.
75
-
76
- Args:
77
- text: The informative text to send to the client.
78
- """
79
- if self._cancelled:
80
- return
81
-
82
- if self._ended:
83
- raise RuntimeError(str(error_resources.StreamAlreadyEnded))
84
-
85
- # Queue a typing activity
86
- def create_activity():
87
- activity = Activity(
88
- type="typing",
89
- text=text,
90
- entities=[
91
- Entity(
92
- type="streaminfo",
93
- stream_type="informative",
94
- stream_sequence=self._sequence_number,
95
- )
96
- ],
97
- )
98
- self._sequence_number += 1
99
- return activity
100
-
101
- self._queue_activity(create_activity)
102
-
103
- def queue_text_chunk(
104
- self, text: str, citations: Optional[List[Citation]] = None
105
- ) -> None:
106
- """
107
- Queues a chunk of partial message text to be sent to the client.
108
-
109
- The text will be sent as quickly as possible to the client.
110
- Chunks may be combined before delivery to the client.
111
-
112
- Args:
113
- text: Partial text of the message to send.
114
- citations: Citations to be included in the message.
115
- """
116
- if self._cancelled:
117
- return
118
- if self._ended:
119
- raise RuntimeError(str(error_resources.StreamAlreadyEnded))
120
-
121
- # Update full message text
122
- self._message += text
123
-
124
- # If there are citations, modify the content so that the sources are numbers instead of [doc1], [doc2], etc.
125
- self._message = CitationUtil.format_citations_response(self._message)
126
-
127
- # Queue the next chunk
128
- self._queue_next_chunk()
129
-
130
- async def end_stream(self) -> None:
131
- """
132
- Ends the stream by sending the final message to the client.
133
- """
134
- if self._ended:
135
- raise RuntimeError(str(error_resources.StreamAlreadyEnded))
136
-
137
- # Queue final message
138
- self._ended = True
139
- self._queue_next_chunk()
140
-
141
- # Wait for the queue to drain
142
- await self.wait_for_queue()
143
-
144
- def set_attachments(self, attachments: List[Attachment]) -> None:
145
- """
146
- Sets the attachments to attach to the final chunk.
147
-
148
- Args:
149
- attachments: List of attachments.
150
- """
151
- self._attachments = attachments
152
-
153
- def set_sensitivity_label(self, sensitivity_label: SensitivityUsageInfo) -> None:
154
- """
155
- Sets the sensitivity label to attach to the final chunk.
156
-
157
- Args:
158
- sensitivity_label: The sensitivity label.
159
- """
160
- self._sensitivity_label = sensitivity_label
161
-
162
- def set_citations(self, citations: List[Citation]) -> None:
163
- """
164
- Sets the citations for the full message.
165
-
166
- Args:
167
- citations: Citations to be included in the message.
168
- """
169
- if citations:
170
- if not self._citations:
171
- self._citations = []
172
-
173
- curr_pos = len(self._citations)
174
-
175
- for citation in citations:
176
- client_citation = ClientCitation(
177
- type="Claim",
178
- position=curr_pos + 1,
179
- appearance={
180
- "type": "DigitalDocument",
181
- "name": citation.title or f"Document #{curr_pos + 1}",
182
- "abstract": CitationUtil.snippet(citation.content, 477),
183
- },
184
- )
185
- curr_pos += 1
186
- self._citations.append(client_citation)
187
-
188
- def set_feedback_loop(self, enable_feedback_loop: bool) -> None:
189
- """
190
- Sets the Feedback Loop in Teams that allows a user to
191
- give thumbs up or down to a response.
192
- Default is False.
193
-
194
- Args:
195
- enable_feedback_loop: If true, the feedback loop is enabled.
196
- """
197
- self._enable_feedback_loop = enable_feedback_loop
198
-
199
- def set_feedback_loop_type(
200
- self, feedback_loop_type: Literal["default", "custom"]
201
- ) -> None:
202
- """
203
- Sets the type of UI to use for the feedback loop.
204
-
205
- Args:
206
- feedback_loop_type: The type of the feedback loop.
207
- """
208
- self._feedback_loop_type = feedback_loop_type
209
-
210
- def set_generated_by_ai_label(self, enable_generated_by_ai_label: bool) -> None:
211
- """
212
- Sets the Generated by AI label in Teams.
213
- Default is False.
214
-
215
- Args:
216
- enable_generated_by_ai_label: If true, the label is added.
217
- """
218
- self._enable_generated_by_ai_label = enable_generated_by_ai_label
219
-
220
- def get_message(self) -> str:
221
- """
222
- Returns the most recently streamed message.
223
- """
224
- return self._message
225
-
226
- async def wait_for_queue(self) -> None:
227
- """
228
- Waits for the outgoing activity queue to be empty.
229
- """
230
- if self._queue_sync:
231
- await self._queue_sync
232
-
233
- def _set_defaults(self, context: "TurnContext"):
234
- if context.activity.channel_id == Channels.ms_teams:
235
- self._is_streaming_channel = True
236
- self._interval = 1.0
237
- elif context.activity.channel_id == Channels.direct_line:
238
- self._is_streaming_channel = True
239
- self._interval = 0.5
240
- elif context.activity.delivery_mode == DeliveryModes.stream:
241
- self._is_streaming_channel = True
242
- self._interval = 0.1
243
-
244
- self._channel_id = context.activity.channel_id
245
-
246
- def _queue_next_chunk(self) -> None:
247
- """
248
- Queues the next chunk of text to be sent to the client.
249
- """
250
- # Are we already waiting to send a chunk?
251
- if self._chunk_queued:
252
- return
253
-
254
- # Queue a chunk of text to be sent
255
- self._chunk_queued = True
256
-
257
- def create_activity():
258
- self._chunk_queued = False
259
- if self._ended:
260
- # Send final message
261
- activity = Activity(
262
- type="message",
263
- text=self._message or "end stream response",
264
- attachments=self._attachments or [],
265
- entities=[
266
- Entity(
267
- type="streaminfo",
268
- stream_type="final",
269
- stream_sequence=self._sequence_number,
270
- )
271
- ],
272
- )
273
- elif self._is_streaming_channel:
274
- # Send typing activity
275
- activity = Activity(
276
- type="typing",
277
- text=self._message,
278
- entities=[
279
- Entity(
280
- type="streaminfo",
281
- stream_type="streaming",
282
- stream_sequence=self._sequence_number,
283
- )
284
- ],
285
- )
286
- else:
287
- return
288
- self._sequence_number += 1
289
- return activity
290
-
291
- self._queue_activity(create_activity)
292
-
293
- def _queue_activity(self, factory: Callable[[], Activity]) -> None:
294
- """
295
- Queues an activity to be sent to the client.
296
- """
297
- self._queue.append(factory)
298
-
299
- # If there's no sync in progress, start one
300
- if not self._queue_sync:
301
- self._queue_sync = asyncio.create_task(self._drain_queue())
302
-
303
- async def _drain_queue(self) -> None:
304
- """
305
- Sends any queued activities to the client until the queue is empty.
306
- """
307
- try:
308
- logger.debug(f"Draining queue with {len(self._queue)} activities.")
309
- while self._queue:
310
- factory = self._queue.pop(0)
311
- activity = factory()
312
- if activity:
313
- await self._send_activity(activity)
314
- except Exception as err:
315
- if (
316
- "403" in str(err)
317
- and self._context.activity.channel_id == Channels.ms_teams
318
- ):
319
- logger.warning("Teams channel stopped the stream.")
320
- self._cancelled = True
321
- else:
322
- logger.error(
323
- f"Error occurred when sending activity while streaming: {type(err).__name__}"
324
- )
325
- raise
326
- finally:
327
- self._queue_sync = None
328
-
329
- async def _send_activity(self, activity: Activity) -> None:
330
- """
331
- Sends an activity to the client and saves the stream ID returned.
332
-
333
- Args:
334
- activity: The activity to send.
335
- """
336
-
337
- streaminfo_entity = None
338
-
339
- if not activity.entities:
340
- streaminfo_entity = Entity(type="streaminfo")
341
- activity.entities = [streaminfo_entity]
342
- else:
343
- for entity in activity.entities:
344
- if hasattr(entity, "type") and entity.type == "streaminfo":
345
- streaminfo_entity = entity
346
- break
347
-
348
- if not streaminfo_entity:
349
- # If no streaminfo entity exists, create one
350
- streaminfo_entity = Entity(type="streaminfo")
351
- activity.entities.append(streaminfo_entity)
352
-
353
- # Set activity ID to the assigned stream ID
354
- if self._stream_id:
355
- activity.id = self._stream_id
356
- streaminfo_entity.stream_id = self._stream_id
357
-
358
- if self._citations and not self._ended:
359
- # Filter out the citations unused in content.
360
- curr_citations = CitationUtil.get_used_citations(
361
- self._message, self._citations
362
- )
363
- if curr_citations:
364
- activity.entities.append(
365
- Entity(
366
- type="https://schema.org/Message",
367
- schema_type="Message",
368
- context="https://schema.org",
369
- id="",
370
- citation=curr_citations,
371
- )
372
- )
373
-
374
- # Add in Powered by AI feature flags
375
- if self._ended:
376
- if self._enable_feedback_loop and self._feedback_loop_type:
377
- # Add feedback loop to streaminfo entity
378
- streaminfo_entity.feedback_loop = {"type": self._feedback_loop_type}
379
- else:
380
- # Add feedback loop enabled to streaminfo entity
381
- streaminfo_entity.feedback_loop_enabled = self._enable_feedback_loop
382
- # Add in Generated by AI
383
- if self._enable_generated_by_ai_label:
384
- activity.add_ai_metadata(self._citations, self._sensitivity_label)
385
-
386
- # Send activity
387
- response = await self._context.send_activity(activity)
388
- await asyncio.sleep(self._interval)
389
-
390
- # Save assigned stream ID
391
- if not self._stream_id and response:
392
- self._stream_id = response.id
@@ -1,2 +0,0 @@
1
- microsoft-agents-hosting-core==0.9.0.dev2
2
- fastapi>=0.104.0