diff --git a/python/samples/02-agents/chat_client/built_in_chat_clients.py b/python/samples/02-agents/chat_client/built_in_chat_clients.py index 8560afcf4f..92f9364714 100644 --- a/python/samples/02-agents/chat_client/built_in_chat_clients.py +++ b/python/samples/02-agents/chat_client/built_in_chat_clients.py @@ -5,7 +5,7 @@ from random import randint from typing import Annotated, Any, Literal -from agent_framework import SupportsChatGetResponse, tool +from agent_framework import Content, Message, SupportsChatGetResponse, tool from agent_framework.azure import ( AzureAIAgentClient, AzureOpenAIAssistantsClient, @@ -117,10 +117,11 @@ async def main(client_name: ClientName = "openai_chat") -> None: client = get_client(client_name) # 1. Configure prompt and streaming mode. - message = "What's the weather in Amsterdam and in Paris?" + prompt = "What's the weather in Amsterdam and in Paris?" + message = [Message(role="user", contents=[Content.from_text(prompt)])] stream = os.getenv("STREAM", "false").lower() == "true" print(f"Client: {client_name}") - print(f"User: {message}") + print(f"User: {prompt}") # 2. Run with context-managed clients. if isinstance(client, OpenAIAssistantsClient | AzureOpenAIAssistantsClient | AzureAIAgentClient): @@ -157,4 +158,4 @@ async def main(client_name: ClientName = "openai_chat") -> None: User: What's the weather in Amsterdam and in Paris? Assistant: The weather in Amsterdam is sunny with a high of 25°C. ...and in Paris it is cloudy with a high of 19°C. -""" +""" \ No newline at end of file diff --git a/python/samples/02-agents/chat_client/chat_response_cancellation.py b/python/samples/02-agents/chat_client/chat_response_cancellation.py index db292786ce..a5dd081844 100644 --- a/python/samples/02-agents/chat_client/chat_response_cancellation.py +++ b/python/samples/02-agents/chat_client/chat_response_cancellation.py @@ -2,6 +2,7 @@ import asyncio +from agent_framework import Content, Message from agent_framework.openai import OpenAIChatClient from dotenv import load_dotenv @@ -28,7 +29,7 @@ async def main() -> None: client = OpenAIChatClient() try: - task = asyncio.create_task(client.get_response(messages=["Tell me a fantasy story."])) + task = asyncio.create_task(client.get_response([Message(role="user", contents=[Content.from_text("Tell me a fantasy story.")])])) await asyncio.sleep(1) task.cancel() await task diff --git a/python/samples/02-agents/chat_client/custom_chat_client.py b/python/samples/02-agents/chat_client/custom_chat_client.py index aaeed76ced..b2d713d378 100644 --- a/python/samples/02-agents/chat_client/custom_chat_client.py +++ b/python/samples/02-agents/chat_client/custom_chat_client.py @@ -146,7 +146,7 @@ async def main() -> None: # Use the chat client directly print("Using chat client directly:") direct_response = await echo_client.get_response( - "Hello, custom chat client!", + [Message(role="user", contents=[Content.from_text("Hello, custom chat client!")])], options={ "uppercase": True, "suffix": "(CUSTOM OPTIONS)", diff --git a/python/samples/05-end-to-end/chatkit-integration/app.py b/python/samples/05-end-to-end/chatkit-integration/app.py index d47ecc6160..939357fbae 100644 --- a/python/samples/05-end-to-end/chatkit-integration/app.py +++ b/python/samples/05-end-to-end/chatkit-integration/app.py @@ -28,7 +28,8 @@ import uvicorn # Agent Framework imports -from agent_framework import Agent, AgentResponseUpdate, FunctionResultContent, Message, Role, tool +#from agent_framework import Agent, AgentResponseUpdate, FunctionResultContent, Message, Role, tool +from agent_framework import Agent, AgentResponseUpdate, Content, Message, Role, tool from agent_framework.azure import AzureOpenAIChatClient # Agent Framework ChatKit integration @@ -75,7 +76,11 @@ # Server configuration SERVER_HOST = "127.0.0.1" # Bind to localhost only for security (local dev) SERVER_PORT = 8001 -SERVER_BASE_URL = f"http://localhost:{SERVER_PORT}" +# Use the frontend origin for generated URLs (upload, preview) so that the browser +# sends them through the Vite dev-server proxy instead of directly to the backend, +# avoiding cross-origin issues. +FRONTEND_PORT = 5171 +SERVER_BASE_URL = f"http://localhost:{FRONTEND_PORT}" # Database configuration DATABASE_PATH = "chatkit_demo.db" @@ -295,7 +300,7 @@ async def _update_thread_title( title_prompt = [ Message( - role=Role.USER, + role="user", text=( f"Generate a very short, concise title (max 40 characters) for a conversation " f"that starts with:\n\n{conversation_context}\n\n" @@ -346,8 +351,6 @@ async def respond( runs the agent, converts the response back to ChatKit events using stream_agent_response, and creates interactive weather widgets when weather data is queried. """ - from agent_framework import FunctionResultContent - if input_user_message is None: logger.debug("Received None user message, skipping") return @@ -389,7 +392,7 @@ async def intercept_stream() -> AsyncIterator[AgentResponseUpdate]: # Check for function results in the update if update.contents: for content in update.contents: - if isinstance(content, FunctionResultContent): + if isinstance(content, Content) and content.type == "function_result": result = content.result # Check if it's a WeatherResponse (string subclass with weather_data attribute) @@ -472,7 +475,7 @@ async def action( weather_data: WeatherData | None = None # Create an agent message asking about the weather - agent_messages = [Message(role=Role.USER, text=f"What's the weather in {city_label}?")] + agent_messages = [Message(role="user", text=f"What's the weather in {city_label}?")] logger.debug(f"Processing weather query: {agent_messages[0].text}") @@ -486,7 +489,7 @@ async def intercept_stream() -> AsyncIterator[AgentResponseUpdate]: # Check for function results in the update if update.contents: for content in update.contents: - if isinstance(content, FunctionResultContent): + if isinstance(content, Content) and content.type == "function_result": result = content.result # Check if it's a WeatherResponse (string subclass with weather_data attribute) @@ -598,8 +601,8 @@ async def upload_file(attachment_id: str, file: UploadFile = File(...)): # noqa # Load the attachment metadata from the data store attachment = await data_store.load_attachment(attachment_id, {"user_id": DEFAULT_USER_ID}) - # Clear the upload_url since upload is complete - attachment.upload_url = None + # Clear the upload_descriptor since upload is complete + attachment.upload_descriptor = None # Save the updated attachment back to the store await data_store.save_attachment(attachment, {"user_id": DEFAULT_USER_ID}) diff --git a/python/samples/05-end-to-end/chatkit-integration/attachment_store.py b/python/samples/05-end-to-end/chatkit-integration/attachment_store.py index 1c3701d927..c3f22191fa 100644 --- a/python/samples/05-end-to-end/chatkit-integration/attachment_store.py +++ b/python/samples/05-end-to-end/chatkit-integration/attachment_store.py @@ -11,7 +11,7 @@ from typing import TYPE_CHECKING, Any from chatkit.store import AttachmentStore -from chatkit.types import Attachment, AttachmentCreateParams, FileAttachment, ImageAttachment +from chatkit.types import Attachment, AttachmentCreateParams, AttachmentUploadDescriptor, FileAttachment, ImageAttachment from pydantic import AnyUrl if TYPE_CHECKING: @@ -87,7 +87,10 @@ async def create_attachment(self, input: AttachmentCreateParams, context: dict[s type="image", mime_type=input.mime_type, name=input.name, - upload_url=AnyUrl(upload_url), + upload_descriptor=AttachmentUploadDescriptor( + url=AnyUrl(upload_url), + method="POST", + ), preview_url=AnyUrl(preview_url), ) else: @@ -97,7 +100,10 @@ async def create_attachment(self, input: AttachmentCreateParams, context: dict[s type="file", mime_type=input.mime_type, name=input.name, - upload_url=AnyUrl(upload_url), + upload_descriptor=AttachmentUploadDescriptor( + url=AnyUrl(upload_url), + method="POST", + ), ) # Save attachment metadata to data store so it's available during upload diff --git a/python/samples/05-end-to-end/chatkit-integration/frontend/vite.config.ts b/python/samples/05-end-to-end/chatkit-integration/frontend/vite.config.ts index ebf0200e51..1c35b309fc 100644 --- a/python/samples/05-end-to-end/chatkit-integration/frontend/vite.config.ts +++ b/python/samples/05-end-to-end/chatkit-integration/frontend/vite.config.ts @@ -13,6 +13,14 @@ export default defineConfig({ target: backendTarget, changeOrigin: true, }, + "/upload": { + target: backendTarget, + changeOrigin: true, + }, + "/preview": { + target: backendTarget, + changeOrigin: true, + }, }, // For production deployments, you need to add your public domains to this list allowedHosts: [