From b624e89e3307e81b974f58792ced9a5ae66261ac Mon Sep 17 00:00:00 2001 From: Jiwon Kim Date: Thu, 20 Nov 2025 15:11:56 -0800 Subject: [PATCH 1/2] Default ThreadItemConverter is able to handle text-only HiddenContextItem contents --- chatkit/agents.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/chatkit/agents.py b/chatkit/agents.py index 5f3b9ca..6fdff22 100644 --- a/chatkit/agents.py +++ b/chatkit/agents.py @@ -690,10 +690,26 @@ async def hidden_context_to_input( ) -> TResponseInputItem | list[TResponseInputItem] | None: """ Convert a HiddenContextItem into input item(s) to send to the model. - Required when HiddenContextItem are used. + Required to override when HiddenContextItems with non-string content are used. """ - raise NotImplementedError( - "HiddenContextItem were present in a user message but Converter.hidden_context_to_input was not implemented" + if not isinstance(item.content, str): + raise NotImplementedError( + "HiddenContextItems with non-string content were present in a user message but a Converter.hidden_context_to_input was not implemented" + ) + + text = ( + "Hidden context for the agent (not shown to the user):\n" + f"\n{item.content}\n" + ) + return Message( + type="message", + content=[ + ResponseInputTextParam( + type="input_text", + text=text, + ) + ], + role="user", ) async def task_to_input( From bf293721de47f839c9465bfc93f0551126c7688e Mon Sep 17 00:00:00 2001 From: Jiwon Kim Date: Thu, 20 Nov 2025 15:20:32 -0800 Subject: [PATCH 2/2] add unit tests --- tests/test_agents.py | 68 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tests/test_agents.py b/tests/test_agents.py index dcd7bd0..8185651 100644 --- a/tests/test_agents.py +++ b/tests/test_agents.py @@ -38,6 +38,7 @@ ResponseContentPartAddedEvent, ) from openai.types.responses.response_file_search_tool_call import Result +from openai.types.responses.response_input_item_param import Message from openai.types.responses.response_output_text import ( AnnotationContainerFileCitation as ResponsesAnnotationContainerFileCitation, ) @@ -77,6 +78,7 @@ CustomTask, DurationSummary, FileSource, + HiddenContextItem, InferenceOptions, Page, TaskItem, @@ -542,6 +544,72 @@ async def test_input_item_converter_user_input_with_tags_throws_by_default(): await simple_to_agent_input(items) +async def test_input_item_converter_for_hidden_context_with_string_content(): + items = [ + HiddenContextItem( + id="123", + content="User pressed the red button", + thread_id=thread.id, + created_at=datetime.now(), + ) + ] + + # The default converter works for string content + items = await simple_to_agent_input(items) + assert len(items) == 1 + assert items[0] == { + "content": [ + { + "text": "Hidden context for the agent (not shown to the user):\n\nUser pressed the red button\n", + "type": "input_text", + }, + ], + "role": "user", + "type": "message", + } + + +async def test_input_item_converter_for_hidden_context_with_non_string_content(): + items = [ + HiddenContextItem( + id="123", + content={"harry": "potter", "hermione": "granger"}, + thread_id=thread.id, + created_at=datetime.now(), + ) + ] + + # Default converter should throw + with pytest.raises(NotImplementedError): + await simple_to_agent_input(items) + + class MyThreadItemConverter(ThreadItemConverter): + async def hidden_context_to_input(self, item: HiddenContextItem): + content = ",".join(item.content.keys()) + return Message( + type="message", + content=[ + ResponseInputTextParam( + type="input_text", text=f"{content}" + ) + ], + role="user", + ) + + items = await MyThreadItemConverter().to_agent_input(items) + assert len(items) == 1 + assert items[0] == { + "content": [ + { + "text": "harry,hermione", + "type": "input_text", + }, + ], + "role": "user", + "type": "message", + } + + async def test_input_item_converter_with_client_tool_call(): items = [ UserMessageItem(