Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

500: Chat error: Expected code to be unreachable, but got: ModelRequest(parts=[SystemPromptPart(content= #1029

Open
1 task done
BatmanofZuhandArrgh opened this issue Mar 2, 2025 · 1 comment

Comments

@BatmanofZuhandArrgh
Copy link

Initial Checks

  • I confirm that I'm using the latest version of Pydantic AI

Description

Hi, has anyone meet this bug yet?

TRace:
Traceback (most recent call last):
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_graph\graph.py", line 228, in iter
yield GraphRun[StateT, DepsT, T](
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\agent.py", line 464, in iter
yield AgentRun(graph_run)
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\agent.py", line 307, in run
async for _ in agent_run:
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\agent.py", line 1298, in anext
return await self._graph_run.anext()
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_graph\graph.py", line 738, in anext
return await self.next(self._next_node)
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_graph\graph.py", line 727, in next
self._next_node = await self.graph.next(node, history, state=state, deps=deps, infer_name=False)
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_graph\graph.py", line 306, in next
next_node = await node.run(ctx)
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai_agent_graph.py", line 237, in run
return await self._make_request(ctx)
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai_agent_graph.py", line 275, in _make_request
model_response, request_usage = await ctx.deps.model.request(
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\models\vertexai.py", line 151, in request
return await super().request(messages, model_settings, model_request_parameters)
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\models\gemini.py", line 137, in request
async with self._make_request(
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\contextlib.py", line 181, in aenter
return await self.gen.anext()
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\models\gemini.py", line 192, in _make_request
sys_prompt_parts, contents = await self._message_to_gemini_content(messages)
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\models\gemini.py", line 291, in _message_to_gemini_content
message_parts.extend(await cls._map_user_prompt(part))
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\models\gemini.py", line 343, in _map_user_prompt
assert_never(item)
File "C:\Users\ASUS.conda\envs\chatbot_py39\lib\site-packages\typing_extensions.py", line 2595, in assert_never
raise AssertionError(f"Expected code to be unreachable, but got: {value}")
AssertionError: Expected code to be unreachable, but got: ModelRequest(parts=[SystemPromptPart(content='You are an AI assistant customer support for...

===================================================

{
"start_timestamp": "2025-03-02T10:35:42.549388Z",
"trace_id": "0195566d0e55c5b9ffde7bcda9dc422f",
"span_id": "eb3788dc1a5f919f",
"parent_span_id": null,
"span_name": "{agent_name} run {prompt=}",
"level": 17,
"service_name": "unknown_service",
"otel_scope_name": "pydantic-ai",
"tags": [],
"created_at": 1740911744112.654,
"end_timestamp": "2025-03-02T10:35:42.567429Z",
"kind": "span",
"message": "agent run prompt=[ModelRequest(parts=[SystemPromptPart(content='You are an AI a...ime.timezone.utc), part_kind='tool-return')], kind='request')]",
"is_exception": true,
"otel_scope_version": "3.6.4",
"service_version": "8c80bb6258e273e58f9db5eb48ee7c669a21346d",
"http_response_status_code": null,
"semantic_attributes": null,
"semantic_span_type": null,
"matched_filter": true,
"is_extra_span": false,
"semantic_details": null,
"day": "2025-03-02",
"duration": 0.0180411,
"otel_status_code": "ERROR",
"otel_status_message": "AssertionError: Expected code to be unreachable, but got: ModelRequest(parts=[SystemPromptPart(content='You are an AI assistant customer support for Jen Beaut...",
"otel_links": [],
"otel_events": [
{
"event_name": "exception",
"event_timestamp": "2025-03-02T10:35:42.564838Z",
"attributes": {
"exception.escaped": "True",
"exception.message": "Expected code to be unreachable, but got: ModelRequest(parts=[SystemPromptPart(content='You are an AI assistant customer support for Jen Beaut...",
"exception.stacktrace": "Traceback (most recent call last):\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_graph\graph.py", line 228, in iter\n yield GraphRun[StateT, DepsT, T](\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\agent.py", line 464, in iter\n yield AgentRun(graph_run)\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\agent.py", line 307, in run\n async for _ in agent_run:\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\agent.py", line 1298, in anext\n return await self._graph_run.anext()\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_graph\graph.py", line 738, in anext\n return await self.next(self._next_node)\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_graph\graph.py", line 727, in next\n self._next_node = await self.graph.next(node, history, state=state, deps=deps, infer_name=False)\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_graph\graph.py", line 306, in next\n next_node = await node.run(ctx)\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\_agent_graph.py", line 237, in run\n return await self._make_request(ctx)\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\_agent_graph.py", line 275, in _make_request\n model_response, request_usage = await ctx.deps.model.request(\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\models\vertexai.py", line 151, in request\n return await super().request(messages, model_settings, model_request_parameters)\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\models\gemini.py", line 137, in request\n async with self._make_request(\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\contextlib.py", line 181, in aenter\n return await self.gen.anext()\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\models\gemini.py", line 192, in _make_request\n sys_prompt_parts, contents = await self._message_to_gemini_content(messages)\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\models\gemini.py", line 291, in _message_to_gemini_content\n message_parts.extend(await cls._map_user_prompt(part))\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\pydantic_ai\models\gemini.py", line 343, in _map_user_prompt\n assert_never(item)\n File "C:\Users\ASUS\.conda\envs\chatbot_py39\lib\site-packages\typing_extensions.py", line 2595, in assert_never\n raise AssertionError(f"Expected code to be unreachable, but got: {value}")\nAssertionError: Expected code to be unreachable, but got: ModelRequest(parts=[SystemPromptPart(content='You are an AI assistant customer support for Jen Beaut...\n",
"exception.type": "AssertionError"
}
}
],
"url_path": null,
"url_query": null,
"url_full": null,
"http_route": null,
"http_method": null,
"attributes": {
"agent": {
"model": {
"service_account_file": null,
"project_id": null,
"region": "us-central1",
"model_publisher": "google",
"url_template": "https://{region}-aiplatform.googleapis.com/v1/projects/{project_id}/locations/{region}/publishers/{model_publisher}/models/{model}:"
},
"name": null,
"end_strategy": "early",
"model_settings": {
"temperature": 0.2,
"top_p": 0.5,
"max_output_tokens": 800
}
},
"agent_name": "agent",
"code.filepath": "utils\base_agent_PAI.py",
"code.function": "chat_once",
"code.lineno": 89,
"logfire.msg_template": "{agent_name} run {prompt=}",
"model_name": "gemini-1.5-flash",
"prompt": [
{
"parts": [
{
"content": "You are an AI assistant customer support for Jen Beauty, a beauty service provider specializing in eyelash extensions, nail care, facial spa treatments, and laser hair removal.\n\nThe customer may want to:\n+ Enquire about our beauty services (e.g., eyelash extensions, nails, facials, laser hair removal)\n+ Book an appointment for a specific service\n+ Modify or cancel an existing booking\n+ Check details about their current appointment (time, service, beautician, etc.)\n+ Ask detailed or complex questions about beauty treatments, aftercare, promotions, and recommendations\nHere is our service information:\n{\n "name": "Jen Beauty",\n "about": "Jen Beauty offers professional nails, manicures, pedicures, lash extensions, facials, waxing, and embroidery services to help you look your best.",\n "booking_policy": "Cancellation policy You can cancel or reschedule anytime before the appointment time.",\n "instagram": "https://www.instagram.com/Jen.Beauty_Sg/",\n "facebook": "https://www.facebook.com/jen.jen.beauty.sg/",\n "rating": 5.0,\n "reviews": 7,\n "opening_hours": {\n "Monday": "10:00 - 22:00",\n "Tuesday": "10:00 - 22:00",\n "Wednesday": "10:00 - 22:00",\n "Thursday": "10:00 - 22:00",\n "Friday": "10:00 - 22:00",\n "Saturday": "10:00 - 22:00",\n "Sunday": "10:00 - 22:00"\n },\n "time_zone": "Singapore Standard Time",\n "address": "21a Haji Ln Singapore, Central Singapore Community Development Council 189214",\n "contact": {\n "phone": "+65 8858 9099",\n "email": "[email protected]",\n "website": "https://jenbeauty.sg/"\n },\n "services": {\n "Eyelash Service": [\n {\n "name": "Eye Lash Class 1:1",\n "duration": "1 hr 15 mins",\n "price": "$78",\n "discount": "-30% for new customer"\n },\n {\n "name": "2D-3D Volume Lash",\n "duration": "1 hr 15 mins",\n "price": "$88",\n "discount": "-30% for new customer",\n "description": "Subtle enhancement for a naturally beautiful, everyday look."\n },\n {\n "name": "YY Lash",\n "duration": "1 hr 15 mins",\n "price": "$88",\n "discount": "-30% for new customer"\n },\n {\n "name": "4D-5D Volume Lash",\n "duration": "1 hr 15 mins",\n "price": "$98",\n "discount": "-30% for new customer"\n },\n {\n "name": "W Lash",\n "duration": "1 hr 15 mins",\n "price": "$98",\n "discount": "-30% for new customer"\n },\n {\n "name": "Wet Thai Lash",\n "duration": "1 hr 15 mins",\n "price": "$98",\n "discount": "-30% for new customer"\n },\n {\n "name": "6D-7D Volume Lash",\n "duration": "1 hr 30 mins",\n "price": "$108",\n "discount": "-30% for new customer",\n "description": "Subtle enhancement for a naturally beautiful, everyday look."\n },\n {\n "name": "8D-9D Volume Lash",\n "duration": "2 hrs",\n "price": "$108",\n "discount": "-30% for new customer",\n "description": "Lush, dramatic lashes for a bold, glamorous effect."\n },\n {\n "name": "Mega Volume 10D up",\n "duration": "2 hrs",\n "price": "$118",\n "discount": "-30% for new customer",\n "description": "High-impact lashes with serious volume for a stunning look."\n },\n {\n "name": "Mega Volume 15D up",\n "duration": "2 hrs",\n "price": "$118",\n "discount": "-30% for new customer",\n "description": "The ultimate in lash volume - dramatic and eye-catching."\n },\n {\n "name": "Eyelash Extension Removal",\n "duration": "10 mins",\n "price": "$10",\n "description": "Gentle eyelash removal"\n }\n ],\n "Nails Service": [\n {\n "name": "Manicure Service (Express)",\n "duration": "45 mins",\n "price": "$48",\n "discount": "-30% for new customer",\n "description": "We understand that your hands and nails are a reflection of your personal style."\n },\n {\n "name": "Pedicure Service (Express)",\n "duration": "45 mins",\n "price": "$58",\n "discount": "-30% for new customer",\n "description": "Our highly skilled nail technicians are passionate about creating stunning nail art and providing top-notch nail care."\n },\n {\n "name": "Manicure Service Gel (Classic)",\n "duration": "1 hr 15 mins",\n "price": "$68",\n "discount": "-30% for new customer",\n "description": "Treat your hands to a pampering session. Enjoy long-lasting, glossy nails that withstand daily wear."\n },\n {\n "name": "Pedicure Service Gel (Classic)",\n "duration": "1 hr 15 mins",\n "price": "$78",\n "discount": "-30% for new customer",\n "description": "Indulgent foot care leaving you with gorgeous, long-lasting color."\n }\n ],\n "Facial Spa": [\n {\n "name": "BB Glow (Facial Spa)",\n "duration": "1 hr 30 mins",\n "price": "$128",\n "discount": "30% for new customer",\n "description": "Durable, foundation-like coverage that minimizes dark spots, redness, and scarring, enhancing your skin\u2019s overall tone, texture, and complexion."\n }\n ],\n "Laser Hair Removal": [\n {\n "name": "Small Areas for Women",\n "duration": "45 mins",\n "price": "$78",\n "discount": "-30% for new customer",\n "description": "Fingers / Toes, Upper Lips & Chin, Under Arms"\n },\n {\n "name": "Small Areas for Men",\n "duration": "45 mins",\n "price": "$98",\n "discount": "-30% for new customer",\n "description": "Fingers / Toes, Upper Lips & Chin, Under Arms"\n },\n {\n "name": "Large Areas (Half) for Women",\n "duration": "1 hr",\n "price": "$88",\n "discount": "-30% for new customer",\n "description": "Upper / Lower Arms, Upper / Lower Legs, Brazilian"\n },\n {\n "name": "Large Areas (Half) for Men",\n "duration": "1 hr",\n "price": "$108",\n "discount": "-30% for new customer",\n "description": "Upper / Lower Arms, Upper / Lower Legs, Brazilian"\n },\n {\n "name": "Large Areas (Full) for Women",\n "duration": "1 hr 15 mins",\n "price": "$108",\n "discount": "-30% for new customer",\n "description": "Full Arms, Full Legs, Brazilian"\n },\n {\n "name": "Large Areas (Full) for Men",\n "duration": "1 hr 15 mins",\n "price": "$128",\n "discount": "-30% for new customer",\n "description": "Full Arms, Full Legs, Brazilian"\n },\n {\n "name": "Full Body Hair Removal for Women",\n "duration": "2 hrs",\n "price": "$158",\n "discount": "-30% for new customer"\n },\n {\n "name": "Full Body Hair Removal for Men",\n "duration": "2 hrs",\n "price": "$178",\n "discount": "-30% for new customer"\n }\n ],\n "Facial Embroidery": [\n {\n "name": "Eyebrow Embroidery",\n "duration": "3 hrs",\n "price": "$628",\n "discount": "-30% for new customer. Long-lasting brow enhancement. Mimics natural hair. Fills gaps and defines shape."\n },\n {\n "name": "Lip Embroidery",\n "duration": "3 hrs",\n "price": "$508",\n "discount": "-30% for new customer. Semi-permanent lip color. Enhances shape and fullness. Natural-looking results."\n }\n ]\n }\n}\n- When booking, ask the customer for the following details:\n+ Services they want\n+ Date & Time they want to book\n+ Customer Name (only first necessary, or nickname is good)\n+ Email\n+ Phone number \n- The customer might not specify the service they want, cuz they want to be there and decide. Don't push them too hard to decide right away, put UNKNOWN if they have not decide yet. \n- Once the customer confirms the booking, respond with: "I will now book the appointment\nYour Appointment ID is a1b2c3d4".Provide a summary of the booking, including all details they provided.\n- When asked to modify customer order, ask the customer to give the id. Modify one appointment at a time. If it matches one of the scheduled booking, give the user all the information about that order, including [Weekday,Date,Time,Appointment ID,Customer Name,Address,Service,Bill($),Duration(hr),Email]. Ask the user to confirm modification. Then after user confirmation, generate "I will now modify the appointment {The Appointment ID that the user gave}". Then provide the customer with a summary of their new order, datetime, prices, and services ordered. \n- To cancel the appointment for the customer, please ask the customer to confirm cancellation. Then after user confirmation, generate "I will now cancel the appointment {The Appointment ID that the user gave}". \n- If a question is too hard, you can't find a satisfactory answer, the customer request to talk to a human customer surport, please generate "I will now transfer the chat to my human colleague!"\n- If the customer has a special request and insist on it, let them know you will transfer the chat to human customer service agent. Then generate "I will now transfer the chat to my human colleague!"\n- If your conversation is confirmed to be done, generate "Thank you for using our service, have a good day!"\n\n\nCurrent schedule:\n[\n {\n "Weekday": "Monday",\n "Date": "1 March, 2025",\n "Time": "6:30PM",\n "Appointment ID": "Z722B9",\n "Customer Name": "John Doe",\n "Service": "4D-5D Volume Lash",\n "Bill($)": 98,\n "Duration": "1 hr 15 mins",\n "Email": "[email protected]"\n },\n {\n "Weekday": "Tuesday",\n "Date": "2 March 2025",\n "Time": "4:00PM",\n "Appointment ID": "OI7892",\n "Customer Name": "Jane Smith",\n "Service": "Manicure Service (Express) + BB Glow (Facial Spa)",\n "Bill($)": 90,\n "Duration": 2 hrs 15 mins,\n "Email": "[email protected]"\n }\n]\nCurrent time is Monday, 20-02-2025, 18:01:31\n\nAssume that there is no overlap in the schedule. Any valid booking time in the future is available.\n",
"dynamic_ref": null,
"part_kind": "system-prompt"
},
{
"content": "Hi booking, YY Lash. March 1st, Im Ben, Ben@gmail",
"timestamp": "2025-03-02T10:35:40.153452+00:00",
"part_kind": "user-prompt"
}
],
"kind": "request"
},
{
"parts": [
{
"tool_name": "final_result",
"args": {
"data": "I will now book the appointment\nYour Appointment ID is a1b2c3d4\nYour appointment is scheduled for Monday, March 1st, 2025 at 6:30PM for YY Lash service.\nYour Appointment ID is a1b2c3d4\nCustomer Name: Ben\nEmail: Ben@gmail\nService: YY Lash\nBill($): 88\nDuration: 1 hr 15 mins"
},
"tool_call_id": null,
"part_kind": "tool-call"
}
],
"model_name": "gemini-1.5-flash-001",
"timestamp": "2025-03-02T10:35:42.526466+00:00",
"kind": "response"
},
{
"parts": [
{
"tool_name": "final_result",
"content": "Final result processed.",
"tool_call_id": null,
"timestamp": "2025-03-02T10:35:42.540499+00:00",
"part_kind": "tool-return"
}
],
"kind": "request"
}
]
},
"attributes_json_schema": "{"type":"object","properties":{"agent":{"type":"object","title":"Agent","x-python-datatype":"dataclass","properties":{"model":{"type":"object","title":"VertexAIModel","x-python-datatype":"dataclass"}}},"agent_name":{},"model_name":{},"prompt":{"type":"array","prefixItems":[{"type":"object","title":"ModelRequest","x-python-datatype":"dataclass","properties":{"parts":{"type":"array","prefixItems":[{"type":"object","title":"SystemPromptPart","x-python-datatype":"dataclass"},{"type":"object","title":"UserPromptPart","x-python-datatype":"dataclass","properties":{"timestamp":{"type":"string","format":"date-time"}}}]}}},{"type":"object","title":"ModelResponse","x-python-datatype":"dataclass","properties":{"parts":{"type":"array","items":{"type":"object","title":"ToolCallPart","x-python-datatype":"dataclass"}},"timestamp":{"type":"string","format":"date-time"}}},{"type":"object","title":"ModelRequest","x-python-datatype":"dataclass","properties":{"parts":{"type":"array","items":{"type":"object","title":"ToolReturnPart","x-python-datatype":"dataclass","properties":{"timestamp":{"type":"string","format":"date-time"}}}}}}]}}}",
"otel_scope_attributes": {},
"service_namespace": "",
"service_instance_id": "4f28e878a7c4450687795e703dd8dc8a",
"process_pid": 12084,
"otel_resource_attributes": {
"process.pid": 12084,
"process.runtime.description": "3.9.21 (main, Dec 11 2024, 16:35:24) [MSC v.1929 64 bit (AMD64)]",
"process.runtime.name": "cpython",
"process.runtime.version": "3.9.21",
"service.instance.id": "4f28e878a7c4450687795e703dd8dc8a",
"service.name": "unknown_service",
"service.version": "8c80bb6258e273e58f9db5eb48ee7c669a21346d",
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": "1.30.0"
},
"telemetry_sdk_name": "opentelemetry",
"telemetry_sdk_language": "python",
"telemetry_sdk_version": "1.30.0",
"deployment_environment": null
}

Example Code

import os
import asyncio
from google.auth import default
from fastapi import HTTPException
import yaml
import logfire
from typing import Optional, Type
from dataclasses import dataclass
from pydantic import BaseModel
from pydantic_ai import Agent, RunContext
import json

from utils.logfire_utils import scrubbing_callback
from utils.base_agent_PAI import BaseChatbot, BaseDeps, BaseResults, load_yaml_config
from utils.prompt_utils import get_agent_prompt, get_summarizer_prompt
from utils.prompts import *

                 
# Logfire logging
LOGFIRE_TOKEN = 'something'
logfire.configure(token=LOGFIRE_TOKEN, scrubbing=logfire.ScrubbingOptions(callback=scrubbing_callback))
logfire.instrument_httpx(capture_all=True)



# Set your Google API Key (Embed it securely)
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "gen-lang-client-0102112891-d56f2c707086.json"
from google.auth import default
creds, project = default()
print(f"Authenticated with project: {project}")

# Dependencies
@dataclass
class SupportDeps(BaseDeps):
    dep: str

class SupportResults(BaseResults):
    data: str

class SupportChatbot(BaseChatbot):
    def __init__(self, 
                 system_prompt: Optional[str] = None, 
                 dep_type: Type[BaseDeps] = SupportDeps,  # ✅ Correct default
                 result_type: Type[BaseResults] = SupportResults, 
                 summmarize_bot: BaseChatbot = None,
                 helper_bot: BaseChatbot = None,
                 tools: list = [],
                 config: dict = None):
        
        super().__init__(
            system_prompt=system_prompt,
            dep_type=dep_type, 
            result_type=result_type,
            tools=tools,
            config=config
        )

        self.summarizer = summmarize_bot
        self.helper_bot = helper_bot

        self.summary_report = []
        self.log = []

    def summarize(self, show: bool = False):
        """Summarizes chat history and extracts order information."""
        content = asyncio.run(self.summarizer.chat_once(self.chat_history))

        try:
            cur_summary = json.loads(content)
        except json.JSONDecodeError:
            print("Error: Could not decode summarizer response!")
            cur_summary = []

        message = "[System: Summarized Report for business owner]"
        if show: print(message)
        self.log.append(message)
        self.summary_report.extend(cur_summary)
        return self.summary_report
    
    def pass2human(self, show = True):
        message = '[System: Passing to human agent.]'
        if show: print(message)
        self.log.append(message)

    def email_biz_owner(self, show = True):
        message = '[System: Emailing business owner.]'
        if show: print(message)
        self.log.append(message)

    def handle_new_order(self, response_txt: str, show: bool):
        '''
        Default implementation. Develop upon if needed for specific use cases 
        '''
        message = '[System: Adding order.]'
        if show: print(message)
        self.log.append(message)
        return response_txt
    
    def handle_modify_order(self, response_txt: str, show: bool):
        '''
        Default implementation. Develop upon if needed for specific use cases 
        '''
        message = '[System: Modifying order.]'
        if show: print(message)
        self.log.append(message)
        return response_txt
    
    def handle_cancel_order(self, response_txt: str, show: bool):
        '''
        Default implementation. Develop upon if needed for specific use cases 
        '''
        message = '[System: Canceling order.]'
        if show: print(message)
        self.log.append(message)
        return response_txt

    def preprocess_response(self, response_txt: str, show: bool):
        actions = {
            BOOKING_TRIGGER_PHRASE: self.handle_new_order,
            MODIFICATION_TRIGGER_PHRASE: self.handle_modify_order,
            CANCELLATION_TRIGGER_PHRASE: self.handle_cancel_order,
        }

        for trigger, action in actions.items():
            if trigger in response_txt:
                # If any of the 3 main task
                action(response_txt, show)
                
                self.summarize(show)
                self.email_biz_owner(show)

                return response_txt

        return response_txt
    
    def postprocess_response(self, response_txt: str, show: bool):
        """Handles exit conditions or human escalation."""
        if FINAL_CS_PHRASE in response_txt:
            return True
        elif FINAL_CS2HUMAN_PHRASE in response_txt:
            self.pass2human(show)
            return True
        return False

    def chat_user(self, deps: Optional[SupportDeps] = None):
        """Interactive chat loop."""
        print("Chatbot initialized. Type 'exit' to quit.")
        while True:
            try:
                user_input = input("User: ")
                if user_input.lower() in ["exit", "quit", "q"]:
                    print("Goodbye!")
                    break

                print(f"Sending Request: {user_input}") 
                response = self.agent.run_sync(
                    user_input, 
                    message_history=self.chat_history,
                    deps=deps)
                self.chat_history = response.all_messages()
                text = response.data.data

                if text:  # Check if a result was returned
                    # Detect tool use and use tools
                    response_txt = self.preprocess_response(text, show = True) 
                    print("Assistant: ", response_txt)
                    
                    # Detect exit condition (end convo or pass2human)
                    exit_condition = self.postprocess_response(response_txt, show = True)
                    if exit_condition:
                        break

            except Exception as e:
                print(f"An error occurred during inference: {e}")
                return None
            

    async def chat_once(self, 
                        input_prompt: str,
                        deps: Optional[BaseDeps] = None,
                        show: bool = True) -> str:
            
            exception = ''  # Store exception if any

            while True:
                try:
                    response = await self.agent.run(
                        input_prompt, 
                        message_history=self.chat_history,
                        deps=deps
                        )
                    self.chat_history = response.all_messages()
                    if response.data.data:  # Check if a result was returned
                        text = response.data.data 
                        text = self.preprocess_response(text, show)
                        self.postprocess_response(text, show)
                        return text
                    else:
                        num_trial += 1
                except Exception as e:
                    exception = e
                    break

            print(f"An error occurred during Gemini inference: {exception}")
            return ''

    def save_log(self, filepath: str = "./out/log.md"):
        with open(filepath, 'w') as f:
            for message in self.log:
                f.write(message + '\n')

    def save_summary(self, filepath: str = "./out/summary.json"):
        with open(filepath, 'w') as f:
            f.write(json.dumps(self.summary_report, indent=4))

if __name__ == "__main__":
    agent_config_path = "configs/base_agent.yaml"
    summarizer_config_path = "configs/summarizer_agent.yaml" # A lot more deterministi
    helper_config_path = "configs/base_agent.yaml"
    prompt_config_path = "configs/prompt_config.yaml"

    agent_config = load_yaml_config(agent_config_path)
    prompt_dict = load_yaml_config(prompt_config_path)
    system_prompt = get_agent_prompt(**prompt_dict)

    summarizer = BaseChatbot(system_prompt=get_summarizer_prompt(), config=load_yaml_config(summarizer_config_path))
    # helper_bot = BaseChatbot(system_prompt=HELPER_PROMPT, config=load_yaml_config(helper_config_path))

    agent = SupportChatbot(
        system_prompt=system_prompt, 
        summmarize_bot=summarizer,
        # helper_bot=helper_bot
        config=agent_config)
    agent.chat_user()

    agent.save_log(filepath = "./out/log.md")
    agent.save_chat_history(filepath = "./out/history.md")
    agent.save_summary(filepath = "./out/summary.md")

Python, Pydantic AI & LLM client version

Gemini 1.5-flash. VertexAI
@BatmanofZuhandArrgh
Copy link
Author

Hope i didn't just reveal any api key in there.

It seems like the model call tools even tho i didn't want to, then input the ModelRequest as input_prompt. Im confused now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant