- Notifications
You must be signed in to change notification settings - Fork17
Update conversation history handling#24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Pull Request Overview
This PR updates conversation history handling to normalize conversation data across different endpoints and provide consistent access to conversation history for guardrails. The main goal is to ensure that conversation history is accessible by all guardrail checks regardless of which API endpoint is used.
- Extracts conversation normalization logic to a dedicated
conversation.pyutility module - Updates
GuardrailAgentto use session-based conversation history when available, falling back to input conversation - Fixes streaming to provide proper conversation history context during output guardrails
Reviewed Changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
src/guardrails/utils/conversation.py | New module providing conversation normalization utilities across different API formats |
src/guardrails/agents.py | Refactors agent conversation handling to use sessions and normalized conversation history |
src/guardrails/client.py | Updates client methods to use normalized conversation handling |
src/guardrails/_streaming.py | Fixes streaming to include conversation history in output guardrail checks |
src/guardrails/resources/responses/responses.py | Updates to use normalized conversation history |
src/guardrails/resources/chat/chat.py | Updates to use normalized conversation history |
tests/unit/test_agents.py | Updates tests for new agent conversation handling patterns |
tests/unit/test_client_sync.py | Updates test assertions for normalized conversation format |
Tip: Customize your code reviews with copilot-instructions.md.Create the file orlearn how to get started.
| """Normalized representation of a conversation item. | ||
| Attributes: | ||
| role: Logical speaker role (user, assistant, system, tool, etc.). | ||
| type: Optional type discriminator for non-message items such as | ||
| ``function_call`` or ``function_call_output``. | ||
| content: Primary text payload for message-like items. | ||
| tool_name: Name of the tool/function associated with the entry. | ||
| arguments: Serialized tool/function arguments when available. | ||
| output: Serialized tool result payload when available. | ||
| call_id: Identifier that links tool calls and outputs. |
CopilotAIOct 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
The ConversationEntry class is missing a comprehensive docstring that should explain its purpose as a normalized conversation item and provide examples of usage.
| """Normalizedrepresentationofaconversationitem. | |
| Attributes: | |
| role:Logicalspeakerrole (user,assistant,system,tool,etc.). | |
| type:Optional typediscriminatorfornon-messageitemssuchas | |
| ``function_call``or``function_call_output``. | |
| content:Primarytextpayloadformessage-likeitems. | |
| tool_name:Nameofthetool/functionassociatedwiththeentry. | |
| arguments:Serializedtool/functionargumentswhenavailable. | |
| output:Serializedtoolresultpayloadwhenavailable. | |
| call_id:Identifierthatlinkstoolcallsandoutputs. | |
| """ | |
| Representsanormalizediteminaconversationhistory,suchasausermessage, | |
| assistantresponse,tool/functioncall,ortooloutput.Thisclassprovidesa | |
| consistentstructureforconversationentries,regardlessoftheoriginating | |
| APIorprovider,enablingguardrailstoprocessandreasonaboutconversation | |
| turnsinauniformway. | |
| Eachentrymayrepresentamessage (fromuser,assistant,orsystem),atool | |
| call (functioninvocation),oratooloutput (functionresult).Thefields | |
| capturethesemanticrole,type,content,andanyassociatedtool/function | |
| metadata. | |
| Attributes: | |
| role:Logicalspeakerrole (e.g.,"user","assistant","system","tool"). | |
| type:Optional typediscriminatorfornon-messageitemssuchas | |
| "function_call"or"function_call_output". | |
| content:Primarytextpayloadformessage-likeitems. | |
| tool_name:Nameofthetool/functionassociatedwiththeentry. | |
| arguments:Serializedtool/functionargumentswhenavailable. | |
| output:Serializedtoolresultpayloadwhenavailable. | |
| call_id:Identifierthatlinkstoolcallsandoutputs. | |
| Example: | |
| >>># User message | |
| >>>entry=ConversationEntry(role="user",content="Hello, assistant!") | |
| >>>entry.to_payload() | |
| {'role':'user','content':'Hello, assistant!'} | |
| >>># Assistant response | |
| >>>entry=ConversationEntry(role="assistant",content="Hello! How can I help you?") | |
| >>>entry.to_payload() | |
| {'role':'assistant','content':'Hello! How can I help you?'} | |
| >>># Tool/function call | |
| >>>entry=ConversationEntry( | |
| ...role="assistant", | |
| ...type="function_call", | |
| ...tool_name="get_weather", | |
| ...arguments='{"location": "London"}', | |
| ...call_id="abc123" | |
| ... ) | |
| >>>entry.to_payload() | |
| { | |
| ...'role':'assistant', | |
| ...'type':'function_call', | |
| ...'tool_name':'get_weather', | |
| ...'arguments':'{"location": "London"}', | |
| ...'call_id':'abc123' | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
In my opinion this is an unnecessary expansion of the current doc string. The current version is concise and matches the codebase style.
| returntext | ||
| return_extract_text(content.get("content")) | ||
| ifisinstance(content,Sequence)andnotisinstance(content,bytes|bytearray): |
CopilotAIOct 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
The union syntaxbytes | bytearray requires Python 3.10+. Consider using(bytes, bytearray) for broader compatibility.
| ifisinstance(content,Sequence)andnotisinstance(content,bytes|bytearray): | |
| ifisinstance(content,Sequence)andnotisinstance(content,(bytes,bytearray)): |
| """Stub tool context carrying name, arguments,andoptional call id.""" | ||
| tool_name:str | ||
| tool_arguments:dict[str,Any] | ||
| tool_arguments:dict[str,Any]|str | ||
| tool_call_id:str|None=None |
CopilotAIOct 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
The union syntaxdict[str, Any] | str andstr | None require Python 3.10+. Consider usingUnion[dict[str, Any], str] andOptional[str] for broader compatibility.
| _user_messages:ContextVar[list[str]]=ContextVar("user_messages",default=[])# noqa: B039 | ||
| # Context variables used to expose conversation information during guardrail checks. | ||
| _agent_session:ContextVar[Any|None]=ContextVar("guardrails_agent_session",default=None) | ||
| _agent_conversation:ContextVar[tuple[dict[str,Any], ...]|None]=ContextVar( |
CopilotAIOct 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
The union syntaxtuple[dict[str, Any], ...] | None requires Python 3.10+. Consider usingOptional[tuple[dict[str, Any], ...]] for broader compatibility.
| llm_stream:Any,# coroutine or async iterator of OpenAI chunks | ||
| preflight_results:list[GuardrailResult], | ||
| input_results:list[GuardrailResult], | ||
| conversation_history:list[dict[str,Any]]|None=None, |
CopilotAIOct 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
The union syntaxlist[dict[str, Any]] | None requires Python 3.10+. Consider usingOptional[list[dict[str, Any]]] for broader compatibility.
| llm_stream:Any,# iterator of OpenAI chunks | ||
| preflight_results:list[GuardrailResult], | ||
| input_results:list[GuardrailResult], | ||
| conversation_history:list[dict[str,Any]]|None=None, |
CopilotAIOct 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
The union syntaxlist[dict[str, Any]] | None requires Python 3.10+. Consider usingOptional[list[dict[str, Any]]] for broader compatibility.
gabor-openai left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
LGTM
bdb0de6 intomainUh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Updates handling of conversation history
conversation.pyhelperprevious_response_idfor conversation history withresponsesendpointGuardrailAgentusessessionif passed intoRunner.run(). Otherwise treats theinputas the conversation history