Python: Bug: AnnotationContent and StreamingAnnotationContent to_element writes CitationType.X, so annotations in a rendered chat history fail to parse
Maintainers usually reply within 3 days
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 82/100
Research direction
Start with the to_element methods of AnnotationContent and StreamingAnnotationContent in the Python contents package, where citation_type is written as an XML attribute. Reproduce by serializing an annotation with tostring and parsing it back with from_element or ChatHistory.from_rendered_prompt. Done means the round trip succeeds from the serialized string, with tests that cover the string path, not just the in-memory element.
Written by the indexing model from the issue text.
Description
Describe the bug
AnnotationContent.to_element() and StreamingAnnotationContent.to_element() store the CitationType enum object in the XML attribute:
if self.citation_type:
element.set("type", self.citation_type)
CitationType is a str, Enum. When the element is serialized, the attribute is written with the enum's str() form, CitationType.FILE_CITATION, not the value file_citation. from_element() then cannot read it back. Any chat message that has an annotation with a citation type breaks as soon as the history is rendered to a prompt string and parsed back (ChatHistory.from_rendered_prompt, which is what prompt templates use for {{$chat_history}} style messages).
The existing round trip tests pass because they never serialize the element to a string, so the enum object stays in memory.
To Reproduce
Run against current main (5b4a3269a), Python 3.13:
from semantic_kernel.contents import ChatHistory, ChatMessageContent, AuthorRole, TextContent
from semantic_kernel.contents.annotation_content import AnnotationContent, CitationType
msg = ChatMessageContent(
role=AuthorRole.ASSISTANT,
items=[
TextContent(text="see [1]"),
AnnotationContent(file_id="file-1", quote="q", start_index=4, end_index=7, citation_type=CitationType.FILE_CITATION),
],
)
history = ChatHistory(messages=[msg])
print(msg.to_prompt())
ChatHistory.from_rendered_prompt(str(history))
Output:
<message role="assistant"><text>see [1]</text><annotation type="CitationType.FILE_CITATION" file_id="file-1" quote="q" start_index="4" end_index="7"></annotation></message>
pydantic_core._pydantic_core.ValidationError: 1 validation error for AnnotationContent
type
Input should be 'url_citation', 'file_path', 'file_citation' or 'container_file_citation' [type=enum, input_value='CitationType.FILE_CITATION', input_type=str]
StreamingAnnotationContent has the same line and fails the same way:
from xml.etree.ElementTree import tostring, fromstring
from semantic_kernel.contents.streaming_annotation_content import StreamingAnnotationContent
c = StreamingAnnotationContent(file_id="f", citation_type=CitationType.FILE_CITATION)
StreamingAnnotationContent.from_element(fromstring(tostring(c.to_element(), encoding="unicode")))
Expected behavior
The attribute should be written as the enum value (type="file_citation") so that from_element can parse it. The fix is to use self.citation_type.value in both to_element methods.
I have a fix with tests ready and can open a PR.
Platform
- Language: Python
- Source: main branch (5b4a3269a)
- OS: Windows, Python 3.13
- Dominant language
- C#
- Stars
- 28.6k
- Forks
- 4.8k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 20
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from microsoft/semantic-kernel
-
Python: Bug: TimePlugin timeZoneOffset and timeZoneName always return an empty stringPossibly taken @ducanhnguyen223 claimed this 1 day ago. Openpython triage
Difficulty 2/5 1-3 hours Newbie friendliness 80/100
microsoft/semantic-kernel#14583 · 1 comment ·
Maintainers usually reply within 3 days
-
.Net: gpt-image-1 is the default image model in the .NET OpenAI connector, and OpenAI shuts it down on October 23Possibly taken @nightcityblade claimed this 11 days ago. Open.NET triage
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
microsoft/semantic-kernel#14526 · 1 comment ·
Maintainers usually reply within 3 days
-
Python: VolatileMemoryStore.get_batch and get_nearest_matches ignore with_embeddings=False (deepcopy result is discarded)Possibly taken @VANDRANKI claimed this 13 days ago. Openpython triage
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
microsoft/semantic-kernel#14522 ·
Maintainers usually reply within 3 days
-
Python: VolatileMemoryStore.get_nearest_match returns an un-awaited coroutine instead of a (MemoryRecord, score) tuplePossibly taken @VANDRANKI claimed this 13 days ago. Openpython triage
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
microsoft/semantic-kernel#14521 ·
Maintainers usually reply within 3 days
-
.Net: Bug: BinaryContent does not decode the %xx escapes of a non-base64 data URIPossibly taken @Laurianti claimed this 13 days ago. Open.NET triage
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
microsoft/semantic-kernel#14518 ·
Maintainers usually reply within 3 days
All issues in microsoft/semantic-kernel
Similar issues
-
area-signalr
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
dotnet/aspnetcore#69842 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 64/100
Maintainers usually reply within 2 days
-
bug needs-triage
Difficulty 2/5 Under an hour Newbie friendliness 78/100
microsoft/microsoft-ui-reactor#1373 ·
Maintainers usually reply within 1 day
-
Client customer-reported KeyVault needs-team-attention question Service Attention
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
Azure/azure-sdk-for-net#63861 · 3 comments · 1 reaction ·
Maintainers usually reply within 1 day
-
:watch: Not Triaged dotnet-csharp/svc fundamentals/subsvc
Difficulty 1/5 Under an hour Newbie friendliness 85/100
Maintainers usually reply within 1 day