Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import asyncio

from agent_framework import Content, Message
from agent_framework.openai import OpenAIChatClient
from dotenv import load_dotenv

Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion python/samples/02-agents/chat_client/custom_chat_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
23 changes: 13 additions & 10 deletions python/samples/05-end-to-end/chatkit-integration/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment on lines +31 to +32
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commented-out import line is not PEP8-formatted (#from ... missing a space) and will trigger ruff E265. Also Role is no longer used anywhere in this file, so keeping it in the agent_framework import will trigger an unused-import lint error (F401). Remove the commented line and drop Role from the import list (or switch back to using Role consistently).

Suggested change
#from agent_framework import Agent, AgentResponseUpdate, FunctionResultContent, Message, Role, tool
from agent_framework import Agent, AgentResponseUpdate, Content, Message, Role, tool
from agent_framework import Agent, AgentResponseUpdate, Content, Message, tool

Copilot uses AI. Check for mistakes.
from agent_framework.azure import AzureOpenAIChatClient

# Agent Framework ChatKit integration
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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}")

Expand All @@ -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)
Expand Down Expand Up @@ -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})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand Down