agent-framework-openai 1.2.0__tar.gz → 1.2.2__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.
- {agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/PKG-INFO +2 -2
- {agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/agent_framework_openai/_chat_client.py +133 -29
- {agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/pyproject.toml +2 -2
- {agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/LICENSE +0 -0
- {agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/README.md +0 -0
- {agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/agent_framework_openai/__init__.py +0 -0
- {agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/agent_framework_openai/_chat_completion_client.py +0 -0
- {agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/agent_framework_openai/_embedding_client.py +0 -0
- {agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/agent_framework_openai/_exceptions.py +0 -0
- {agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/agent_framework_openai/_shared.py +0 -0
- {agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/agent_framework_openai/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-framework-openai
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
4
|
Summary: OpenAI integrations for Microsoft Agent Framework.
|
|
5
5
|
Author-email: Microsoft <af-support@microsoft.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.14
|
|
17
17
|
Classifier: Typing :: Typed
|
|
18
18
|
License-File: LICENSE
|
|
19
|
-
Requires-Dist: agent-framework-core>=1.2.
|
|
19
|
+
Requires-Dist: agent-framework-core>=1.2.2,<2
|
|
20
20
|
Requires-Dist: openai>=1.99.0,<3
|
|
21
21
|
Project-URL: homepage, https://aka.ms/agent-framework
|
|
22
22
|
Project-URL: issues, https://github.com/microsoft/agent-framework/issues
|
{agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/agent_framework_openai/_chat_client.py
RENAMED
|
@@ -241,6 +241,85 @@ OpenAIChatOptionsT = TypeVar(
|
|
|
241
241
|
# endregion
|
|
242
242
|
|
|
243
243
|
|
|
244
|
+
# region Helpers
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _annotations_to_output_text(annotations: Sequence[Annotation] | None) -> list[dict[str, Any]]:
|
|
248
|
+
"""Convert framework `Annotation` objects to Responses API `output_text` annotation dicts.
|
|
249
|
+
|
|
250
|
+
Citations from `file_search`, `code_interpreter` file paths, and url citations all collapse
|
|
251
|
+
to `Annotation(type="citation", ...)` in the framework. The original API form is recovered
|
|
252
|
+
here so assistant messages roundtrip cleanly through history forwarding.
|
|
253
|
+
|
|
254
|
+
Each Responses API annotation dict carries at most one `start_index`/`end_index` pair, so an
|
|
255
|
+
`Annotation` with multiple `annotated_regions` is fanned out into one entry per region.
|
|
256
|
+
Regions missing valid integer span bounds are skipped.
|
|
257
|
+
"""
|
|
258
|
+
if not annotations:
|
|
259
|
+
return []
|
|
260
|
+
out: list[dict[str, Any]] = []
|
|
261
|
+
for annotation in annotations:
|
|
262
|
+
if annotation.get("type") != "citation":
|
|
263
|
+
continue
|
|
264
|
+
props = annotation.get("additional_properties") or {}
|
|
265
|
+
regions = annotation.get("annotated_regions") or []
|
|
266
|
+
file_id = annotation.get("file_id")
|
|
267
|
+
url = annotation.get("url")
|
|
268
|
+
title = annotation.get("title")
|
|
269
|
+
container_id = props.get("container_id")
|
|
270
|
+
|
|
271
|
+
if container_id and file_id:
|
|
272
|
+
for region in regions:
|
|
273
|
+
start = region.get("start_index")
|
|
274
|
+
end = region.get("end_index")
|
|
275
|
+
if not (isinstance(start, int) and isinstance(end, int)):
|
|
276
|
+
continue
|
|
277
|
+
entry: dict[str, Any] = {
|
|
278
|
+
"type": "container_file_citation",
|
|
279
|
+
"container_id": container_id,
|
|
280
|
+
"file_id": file_id,
|
|
281
|
+
"start_index": start,
|
|
282
|
+
"end_index": end,
|
|
283
|
+
}
|
|
284
|
+
if url:
|
|
285
|
+
entry["filename"] = url
|
|
286
|
+
out.append(entry)
|
|
287
|
+
elif url and not file_id and regions:
|
|
288
|
+
for region in regions:
|
|
289
|
+
start = region.get("start_index")
|
|
290
|
+
end = region.get("end_index")
|
|
291
|
+
if not (isinstance(start, int) and isinstance(end, int)):
|
|
292
|
+
continue
|
|
293
|
+
out.append({
|
|
294
|
+
"type": "url_citation",
|
|
295
|
+
"url": url,
|
|
296
|
+
"title": title or "",
|
|
297
|
+
"start_index": start,
|
|
298
|
+
"end_index": end,
|
|
299
|
+
})
|
|
300
|
+
elif file_id and url:
|
|
301
|
+
entry = {
|
|
302
|
+
"type": "file_citation",
|
|
303
|
+
"file_id": file_id,
|
|
304
|
+
"filename": url,
|
|
305
|
+
}
|
|
306
|
+
if (idx := props.get("index")) is not None:
|
|
307
|
+
entry["index"] = idx
|
|
308
|
+
out.append(entry)
|
|
309
|
+
elif file_id:
|
|
310
|
+
entry = {
|
|
311
|
+
"type": "file_path",
|
|
312
|
+
"file_id": file_id,
|
|
313
|
+
}
|
|
314
|
+
if (idx := props.get("index")) is not None:
|
|
315
|
+
entry["index"] = idx
|
|
316
|
+
out.append(entry)
|
|
317
|
+
return out
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
# endregion
|
|
321
|
+
|
|
322
|
+
|
|
244
323
|
# region ResponsesClient
|
|
245
324
|
|
|
246
325
|
|
|
@@ -1374,7 +1453,7 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
|
|
1374
1453
|
return {
|
|
1375
1454
|
"type": "output_text",
|
|
1376
1455
|
"text": content.text,
|
|
1377
|
-
"annotations":
|
|
1456
|
+
"annotations": _annotations_to_output_text(getattr(content, "annotations", None)),
|
|
1378
1457
|
}
|
|
1379
1458
|
return {
|
|
1380
1459
|
"type": "input_text",
|
|
@@ -1522,6 +1601,13 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
|
|
1522
1601
|
"approve": content.approved,
|
|
1523
1602
|
}
|
|
1524
1603
|
case "hosted_file":
|
|
1604
|
+
# `input_file` is an input-only content type in the Responses API and is rejected
|
|
1605
|
+
# inside an assistant message. Hosted-file content on an assistant message
|
|
1606
|
+
# represents a citation produced by a hosted tool (e.g., file_search) and cannot be
|
|
1607
|
+
# meaningfully replayed as input — drop it. The accompanying text annotations carry
|
|
1608
|
+
# the citation context for round-tripping.
|
|
1609
|
+
if role == "assistant":
|
|
1610
|
+
return {}
|
|
1525
1611
|
return {
|
|
1526
1612
|
"type": "input_file",
|
|
1527
1613
|
"file_id": content.file_id,
|
|
@@ -2502,45 +2588,63 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
|
|
2502
2588
|
|
|
2503
2589
|
ann_type = _get_ann_value("type")
|
|
2504
2590
|
ann_file_id = _get_ann_value("file_id")
|
|
2591
|
+
# Hosted-file citations attach as text annotations (matching the non-streaming path)
|
|
2592
|
+
# so they don't roundtrip as standalone `input_file` items in assistant history.
|
|
2505
2593
|
if ann_type == "file_path":
|
|
2506
2594
|
if ann_file_id:
|
|
2595
|
+
annotation_obj = Annotation(
|
|
2596
|
+
type="citation",
|
|
2597
|
+
file_id=str(ann_file_id),
|
|
2598
|
+
additional_properties={
|
|
2599
|
+
"annotation_index": event.annotation_index,
|
|
2600
|
+
"index": _get_ann_value("index"),
|
|
2601
|
+
},
|
|
2602
|
+
raw_representation=annotation,
|
|
2603
|
+
)
|
|
2507
2604
|
contents.append(
|
|
2508
|
-
Content.
|
|
2509
|
-
file_id=str(ann_file_id),
|
|
2510
|
-
additional_properties={
|
|
2511
|
-
"annotation_index": event.annotation_index,
|
|
2512
|
-
"index": _get_ann_value("index"),
|
|
2513
|
-
},
|
|
2514
|
-
raw_representation=event,
|
|
2515
|
-
)
|
|
2605
|
+
Content.from_text(text="", annotations=[annotation_obj], raw_representation=event)
|
|
2516
2606
|
)
|
|
2517
2607
|
elif ann_type == "file_citation":
|
|
2518
2608
|
if ann_file_id:
|
|
2609
|
+
ann_filename = _get_ann_value("filename")
|
|
2610
|
+
annotation_obj = Annotation(
|
|
2611
|
+
type="citation",
|
|
2612
|
+
file_id=str(ann_file_id),
|
|
2613
|
+
url=ann_filename,
|
|
2614
|
+
additional_properties={
|
|
2615
|
+
"annotation_index": event.annotation_index,
|
|
2616
|
+
"index": _get_ann_value("index"),
|
|
2617
|
+
},
|
|
2618
|
+
raw_representation=annotation,
|
|
2619
|
+
)
|
|
2519
2620
|
contents.append(
|
|
2520
|
-
Content.
|
|
2521
|
-
file_id=str(ann_file_id),
|
|
2522
|
-
additional_properties={
|
|
2523
|
-
"annotation_index": event.annotation_index,
|
|
2524
|
-
"filename": _get_ann_value("filename"),
|
|
2525
|
-
"index": _get_ann_value("index"),
|
|
2526
|
-
},
|
|
2527
|
-
raw_representation=event,
|
|
2528
|
-
)
|
|
2621
|
+
Content.from_text(text="", annotations=[annotation_obj], raw_representation=event)
|
|
2529
2622
|
)
|
|
2530
2623
|
elif ann_type == "container_file_citation":
|
|
2531
2624
|
if ann_file_id:
|
|
2625
|
+
ann_filename = _get_ann_value("filename")
|
|
2626
|
+
ann_start = _get_ann_value("start_index")
|
|
2627
|
+
ann_end = _get_ann_value("end_index")
|
|
2628
|
+
annotation_obj = Annotation(
|
|
2629
|
+
type="citation",
|
|
2630
|
+
file_id=str(ann_file_id),
|
|
2631
|
+
url=ann_filename,
|
|
2632
|
+
additional_properties={
|
|
2633
|
+
"annotation_index": event.annotation_index,
|
|
2634
|
+
"container_id": _get_ann_value("container_id"),
|
|
2635
|
+
},
|
|
2636
|
+
raw_representation=annotation,
|
|
2637
|
+
)
|
|
2638
|
+
if ann_start is not None and ann_end is not None:
|
|
2639
|
+
annotation_obj["annotated_regions"] = [
|
|
2640
|
+
TextSpanRegion(
|
|
2641
|
+
type="text_span",
|
|
2642
|
+
start_index=ann_start,
|
|
2643
|
+
end_index=ann_end,
|
|
2644
|
+
)
|
|
2645
|
+
]
|
|
2532
2646
|
contents.append(
|
|
2533
|
-
Content.
|
|
2534
|
-
file_id=str(ann_file_id),
|
|
2535
|
-
additional_properties={
|
|
2536
|
-
"annotation_index": event.annotation_index,
|
|
2537
|
-
"container_id": _get_ann_value("container_id"),
|
|
2538
|
-
"filename": _get_ann_value("filename"),
|
|
2539
|
-
"start_index": _get_ann_value("start_index"),
|
|
2540
|
-
"end_index": _get_ann_value("end_index"),
|
|
2541
|
-
},
|
|
2542
|
-
raw_representation=event,
|
|
2543
|
-
)
|
|
2647
|
+
Content.from_text(text="", annotations=[annotation_obj], raw_representation=event)
|
|
2544
2648
|
)
|
|
2545
2649
|
elif ann_type == "url_citation":
|
|
2546
2650
|
ann_url = _get_ann_value("url")
|
|
@@ -4,7 +4,7 @@ description = "OpenAI integrations for Microsoft Agent Framework."
|
|
|
4
4
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
7
|
-
version = "1.2.
|
|
7
|
+
version = "1.2.2"
|
|
8
8
|
license-files = ["LICENSE"]
|
|
9
9
|
urls.homepage = "https://aka.ms/agent-framework"
|
|
10
10
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
|
@@ -23,7 +23,7 @@ classifiers = [
|
|
|
23
23
|
"Typing :: Typed",
|
|
24
24
|
]
|
|
25
25
|
dependencies = [
|
|
26
|
-
"agent-framework-core>=1.2.
|
|
26
|
+
"agent-framework-core>=1.2.2,<2",
|
|
27
27
|
"openai>=1.99.0,<3",
|
|
28
28
|
]
|
|
29
29
|
|
|
File without changes
|
|
File without changes
|
{agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/agent_framework_openai/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/agent_framework_openai/_exceptions.py
RENAMED
|
File without changes
|
{agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/agent_framework_openai/_shared.py
RENAMED
|
File without changes
|
{agent_framework_openai-1.2.0 → agent_framework_openai-1.2.2}/agent_framework_openai/py.typed
RENAMED
|
File without changes
|