Skip to content

Commit 16f6fa4

Browse files
authored
Merge branch 'main' into feat/CPK-7193-inspector-threads-clean
2 parents 62b5252 + ecfb6f0 commit 16f6fa4

7 files changed

Lines changed: 45 additions & 31 deletions

File tree

docs/lib/providers/posthog-provider.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ import { usePathname } from "next/navigation";
77
import { normalizePathnameForAnalytics } from "@/lib/analytics-utils";
88

99
const POSTHOG_KEY = process.env.NEXT_PUBLIC_POSTHOG_KEY;
10-
const POSTHOG_HOST = process.env.NEXT_PUBLIC_POSTHOG_HOST;
10+
// Reverse-proxied via /ingest/* rewrites in next.config.mjs so requests
11+
// flow through docs.copilotkit.ai instead of *.i.posthog.com — bypasses
12+
// ad blockers / tracking-protection that target the PostHog hostname.
13+
const POSTHOG_HOST = "/ingest";
14+
const POSTHOG_UI_HOST = "https://eu.posthog.com";
1115

1216
export function PostHogProvider({ children }: { children: React.ReactNode }) {
1317
const pathname = usePathname();
@@ -24,12 +28,7 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {
2428

2529
// Initialize PostHog once (only on mount)
2630
useEffect(() => {
27-
if (
28-
POSTHOG_KEY &&
29-
POSTHOG_HOST &&
30-
!posthog?.__loaded &&
31-
!isInitializedRef.current
32-
) {
31+
if (POSTHOG_KEY && !posthog?.__loaded && !isInitializedRef.current) {
3332
isInitializedRef.current = true;
3433

3534
// Read sessionId from URL at initialization time
@@ -94,6 +93,7 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {
9493

9594
posthog.init(POSTHOG_KEY, {
9695
api_host: POSTHOG_HOST,
96+
ui_host: POSTHOG_UI_HOST,
9797
person_profiles: "identified_only",
9898
bootstrap: initSessionId
9999
? {
@@ -117,7 +117,7 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {
117117

118118
// Capture pageview only after PostHog is initialized
119119
useEffect(() => {
120-
if (POSTHOG_KEY && POSTHOG_HOST && posthog?.__loaded) {
120+
if (POSTHOG_KEY && posthog?.__loaded) {
121121
try {
122122
const normalizedPathname = normalizePathnameForAnalytics(pathname);
123123
posthog.capture("$pageview", {

docs/middleware.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,6 @@ export const config = {
149149
* - _next/image (image optimization files)
150150
* - favicon.ico (favicon file)
151151
*/
152-
"/((?!api|_next/static|_next/image|favicon.ico).*)",
152+
"/((?!api|ingest|_next/static|_next/image|favicon.ico).*)",
153153
],
154154
};

docs/next.config.mjs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,15 @@ const config = {
140140

141141
return {
142142
beforeFiles: [
143+
// PostHog reverse proxy — routes analytics through our domain to bypass ad blockers
144+
{
145+
source: '/ingest/static/:path*',
146+
destination: 'https://eu-assets.i.posthog.com/static/:path*',
147+
},
148+
{
149+
source: '/ingest/:path*',
150+
destination: 'https://eu.i.posthog.com/:path*',
151+
},
143152
// Map /guides/* to /built-in-agent/guides/* (legacy path)
144153
{
145154
source: '/guides/:path*',

showcase/integrations/built-in-agent/src/app/demos/gen-ui-interrupt/page.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
// the user decides.
1414

1515
import React, { useRef } from "react";
16-
import { CopilotKit } from "@copilotkit/react-core";
1716
import {
17+
CopilotKitProvider,
1818
CopilotChat,
1919
useConfigureSuggestions,
2020
useFrontendTool,
@@ -35,13 +35,13 @@ type PickerResult =
3535

3636
export default function GenUiInterruptDemo() {
3737
return (
38-
<CopilotKit runtimeUrl="/api/copilotkit" agent="gen-ui-interrupt">
38+
<CopilotKitProvider runtimeUrl="/api/copilotkit" useSingleEndpoint>
3939
<div className="flex justify-center items-center h-screen w-full">
4040
<div className="h-full w-full max-w-4xl">
4141
<Chat />
4242
</div>
4343
</div>
44-
</CopilotKit>
44+
</CopilotKitProvider>
4545
);
4646
}
4747

@@ -117,6 +117,6 @@ function Chat() {
117117
// @endregion[frontend-promise-handler]
118118

119119
return (
120-
<CopilotChat agentId="gen-ui-interrupt" className="h-full rounded-2xl" />
120+
<CopilotChat className="h-full rounded-2xl" />
121121
);
122122
}

showcase/integrations/built-in-agent/src/app/demos/interrupt-headless/page.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
// — equivalent UX, different mechanism.
2020

2121
import React, { useRef, useState } from "react";
22-
import { CopilotKit } from "@copilotkit/react-core";
2322
import {
23+
CopilotKitProvider,
2424
CopilotChat,
2525
useConfigureSuggestions,
2626
useFrontendTool,
@@ -47,9 +47,9 @@ const DEFAULT_SLOTS: TimeSlot[] = [
4747

4848
export default function InterruptHeadlessDemo() {
4949
return (
50-
<CopilotKit runtimeUrl="/api/copilotkit" agent="interrupt-headless">
50+
<CopilotKitProvider runtimeUrl="/api/copilotkit" useSingleEndpoint>
5151
<Layout />
52-
</CopilotKit>
52+
</CopilotKitProvider>
5353
);
5454
}
5555

@@ -129,7 +129,7 @@ function Layout() {
129129
<div className="grid h-screen grid-cols-[1fr_420px] bg-[#FAFAFC]">
130130
<AppSurface pending={pending} resolve={resolve} />
131131
<div className="border-l border-[#DBDBE5] bg-white">
132-
<CopilotChat agentId="interrupt-headless" className="h-full" />
132+
<CopilotChat className="h-full" />
133133
</div>
134134
</div>
135135
);

showcase/integrations/langroid/src/agents/multimodal_agent.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,22 @@ def _normalize_part(part: Any) -> dict[str, Any] | None:
116116
- ``{"type": "binary", "mimeType": "...", "data": "<b64>"}`` (legacy)
117117
- ``{"type": "image_url", "image_url": {"url": "data:..."}}`` (already OpenAI shape)
118118
- bare strings (treated as text).
119+
- Pydantic model instances (e.g. ``TextInputContent``, ``ImageInputContent``,
120+
``DocumentInputContent`` from ``ag_ui.core``) — converted to dicts via
121+
``model_dump()`` so the rest of the function can use ``.get()``.
119122
"""
120123
if isinstance(part, str):
121124
if not part:
122125
return None
123126
return {"type": "text", "text": part}
127+
# Pydantic model instances (from ag_ui.core deserialization) are not
128+
# dicts but expose model_dump(). Convert once so the rest of the
129+
# function can use dict-style .get() access uniformly.
124130
if not isinstance(part, dict):
125-
return None
131+
if hasattr(part, "model_dump"):
132+
part = part.model_dump(by_alias=True)
133+
else:
134+
return None
126135
ptype = part.get("type")
127136

128137
if ptype == "text":

showcase/integrations/ms-agent-python/src/agents/multimodal_agent.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,10 @@
3030
- showcase/integrations/langgraph-python/src/agents/multimodal_agent.py
3131
"""
3232

33-
from __future__ import annotations
34-
3533
import base64
3634
import io
3735
from textwrap import dedent
38-
from typing import Any
36+
from typing import Any, Optional, Tuple
3937

4038
from agent_framework import Agent, BaseChatClient
4139
from agent_framework_ag_ui import AgentFrameworkAgent
@@ -101,7 +99,7 @@ def _extract_pdf_text(b64: str) -> str:
10199
return ""
102100

103101

104-
def _classify_attachment_part(part: Any) -> tuple[str, str, str] | None:
102+
def _classify_attachment_part(part: Any) -> Optional[Tuple[str, str, str]]:
105103
"""Inspect a content part and return (kind, mime, base64_payload).
106104
107105
``kind`` is one of ``"image"``, ``"pdf"``, ``"other"``. Returns ``None``
@@ -124,7 +122,7 @@ def _classify_attachment_part(part: Any) -> tuple[str, str, str] | None:
124122

125123
if part_type == "image_url":
126124
image_url = part.get("image_url")
127-
url: str | None = None
125+
url: Optional[str] = None
128126
if isinstance(image_url, str):
129127
url = image_url
130128
elif isinstance(image_url, dict):
@@ -217,14 +215,12 @@ def _flatten_messages(self, messages: Any) -> Any:
217215
rewritten.append({**message, "content": new_parts})
218216
return rewritten
219217

220-
async def run(self, *args: Any, **kwargs: Any) -> Any: # type: ignore[override]
221-
# AG-UI may hand us messages via a positional or keyword argument;
222-
# normalize both shapes before delegating to the base implementation.
223-
if "messages" in kwargs:
224-
kwargs["messages"] = self._flatten_messages(kwargs["messages"])
225-
elif args and isinstance(args[0], list):
226-
args = (self._flatten_messages(args[0]), *args[1:])
227-
return await super().run(*args, **kwargs)
218+
async def run(self, input_data: dict[str, Any]): # type: ignore[override]
219+
messages = input_data.get("messages")
220+
if isinstance(messages, list):
221+
input_data = {**input_data, "messages": self._flatten_messages(messages)}
222+
async for event in super().run(input_data):
223+
yield event
228224

229225

230226
def create_multimodal_agent(chat_client: BaseChatClient) -> AgentFrameworkAgent:

0 commit comments

Comments
 (0)