Skip to content

feat(telemetry): Adding Reo#2875

Open
LuisValdesZero wants to merge 2 commits intomainfrom
feat/add-reo-to-telemetry
Open

feat(telemetry): Adding Reo#2875
LuisValdesZero wants to merge 2 commits intomainfrom
feat/add-reo-to-telemetry

Conversation

@LuisValdesZero
Copy link
Contributor

@LuisValdesZero LuisValdesZero commented Dec 17, 2025

What does this PR do?

Adding Reo to telemetry

Checklist

  • I have read the Contribution Guide
  • If the PR changes or adds functionality, I have updated the relevant documentation

Summary by CodeRabbit

  • Chores
    • Enhanced telemetry data collection infrastructure for usage analytics.

✏️ Tip: You can customize this high-level summary in your review settings.

Signed-off-by: Luis Valdes <luis@copilotkit.ai>
@vercel
Copy link
Contributor

vercel bot commented Dec 17, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
docs Ready Ready Preview, Comment Dec 18, 2025 3:24am
examples-coagents-ai-travel-app Ready Ready Preview, Comment Dec 18, 2025 3:24am
examples-coagents-research-canvas-ui Ready Ready Preview, Comment Dec 18, 2025 3:24am
1 Skipped Deployment
Project Deployment Review Updated (UTC)
examples-coagents-ai-researcher-ui Ignored Ignored Dec 18, 2025 3:24am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 17, 2025

Walkthrough

A POST request to an external telemetry ingestion endpoint is added to the telemetry client, sending event data including source, activity type, event details, and computed properties. The request uses a public API key from environment configuration.

Changes

Cohort / File(s) Summary
Telemetry Integration
CopilotKit/packages/shared/src/telemetry/telemetry-client.ts
Added external POST request to https://ingest.reo.dev/api/product/usage after event logging, sending JSON payload with source, activity_type, event, and ordered properties; uses Content-Type application/json header and X-API-KEY from NEXT_PUBLIC_REO_KEY environment variable

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Verify the external endpoint URL and its intended purpose
  • Confirm the environment variable NEXT_PUBLIC_REO_KEY is properly documented and configured
  • Note: Consider adding error handling or retry logic for the external POST request to prevent silent failures
  • Validate the JSON payload structure aligns with the ingestion service's expectations

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(telemetry): Adding Reo' clearly and specifically describes the main change: integrating Reo into the telemetry system, which aligns with the changeset that adds an external POST request to a Reo API endpoint.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/add-reo-to-telemetry

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
CopilotKit/packages/shared/src/telemetry/telemetry-client.ts (1)

103-118: Consider extracting to a separate client for consistency.

The Reo telemetry call is implemented inline, while the Scarf telemetry (lines 99-101) uses a separate scarfClient. For consistency and maintainability, consider extracting this to a separate reoClient module, similar to the scarfClient pattern. This would:

  • Improve code organization and reusability
  • Make it easier to add additional error handling and resilience patterns
  • Provide a single place to configure Reo-specific behavior

Example structure:

// In a new file: reo-client.ts
class ReoClient {
  private apiKey: string;
  private baseUrl: string;

  constructor() {
    this.apiKey = process.env.NEXT_PUBLIC_REO_KEY || "";
    this.baseUrl = "https://ingest.reo.dev/api/product/usage";
  }

  async logEvent({ event, properties }: { event: string; properties: Record<string, any> }) {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), 5000);

    try {
      await fetch(this.baseUrl, {
        method: "POST",
        signal: controller.signal,
        headers: {
          "Content-Type": "application/json",
          "X-API-KEY": this.apiKey,
        },
        body: JSON.stringify({
          payload: {
            source: "TELEMETRY",
            activity_type: "COPILOTKIT_EVENT",
            event,
            properties,
          }
        })
      });
    } catch (error) {
      // Silently fail
    } finally {
      clearTimeout(timeoutId);
    }
  }
}

export default new ReoClient();

Then in telemetry-client.ts:

import reoClient from "./reo-client";

// In capture method:
await reoClient.logEvent({
  event,
  properties: orderedPropertiesWithGlobal,
});
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e2f2bcd and 1f06223.

📒 Files selected for processing (1)
  • CopilotKit/packages/shared/src/telemetry/telemetry-client.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)

Use ESLint configuration from CopilotKit/utilities/eslint-config-custom for consistent linting across the monorepo

Files:

  • CopilotKit/packages/shared/src/telemetry/telemetry-client.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/frontend-development.mdc)

**/*.{ts,tsx}: Use TypeScript for better type safety in React component development
Implement proper error handling in React components
Use CopilotKit provided hooks (useCopilotChat, useCopilotAction, useCopilotReadable) and utilities in React components
Maintain consistent styling with Tailwind CSS in UI components
Implement responsive design in UI components
Use CopilotProvider at the root of the application to wrap all app components

**/*.{ts,tsx}: Use 'auto' mode (default) in CopilotChat suggestions prop to generate suggestions automatically at the start of chat and after every turn
Use 'manual' mode in CopilotChat suggestions prop only when you need full programmatic control via setSuggestions or generateSuggestions from useCopilotChat hook
Configure suggestions via useCopilotChatSuggestions hook to register configuration for auto-generation system

Files:

  • CopilotKit/packages/shared/src/telemetry/telemetry-client.ts

Comment on lines +103 to +118
const reoUrl = "https://ingest.reo.dev/api/product/usage"
await fetch(reoUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": process.env.NEXT_PUBLIC_REO_KEY || "",
},
body: JSON.stringify({
payload: {
source: "TELEMETRY",
activity_type: "COPILOTKIT_EVENT",
event,
properties: orderedPropertiesWithGlobal,
}
})
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Add error handling to prevent telemetry failures from crashing.

The fetch call has no error handling. If the Reo endpoint is unreachable, slow, or returns an error, the unhandled rejection will propagate and could crash the application or cause the entire capture method to fail. Telemetry should fail gracefully without impacting the main application flow.

Apply this diff to add error handling:

     const reoUrl = "https://ingest.reo.dev/api/product/usage"
-    await fetch(reoUrl, {
-      method: "POST",
-      headers: {
-        "Content-Type": "application/json",
-        "X-API-KEY": process.env.NEXT_PUBLIC_REO_KEY || "",
-      },
-      body: JSON.stringify({
-        payload: {
-          source: "TELEMETRY",
-          activity_type: "COPILOTKIT_EVENT",
-          event,
-          properties: orderedPropertiesWithGlobal,
-        }
-      })
-    });
+    try {
+      await fetch(reoUrl, {
+        method: "POST",
+        headers: {
+          "Content-Type": "application/json",
+          "X-API-KEY": process.env.NEXT_PUBLIC_REO_KEY || "",
+        },
+        body: JSON.stringify({
+          payload: {
+            source: "TELEMETRY",
+            activity_type: "COPILOTKIT_EVENT",
+            event,
+            properties: orderedPropertiesWithGlobal,
+          }
+        })
+      });
+    } catch (error) {
+      // Silently fail - telemetry errors should not impact application
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const reoUrl = "https://ingest.reo.dev/api/product/usage"
await fetch(reoUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": process.env.NEXT_PUBLIC_REO_KEY || "",
},
body: JSON.stringify({
payload: {
source: "TELEMETRY",
activity_type: "COPILOTKIT_EVENT",
event,
properties: orderedPropertiesWithGlobal,
}
})
});
const reoUrl = "https://ingest.reo.dev/api/product/usage"
try {
await fetch(reoUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": process.env.NEXT_PUBLIC_REO_KEY || "",
},
body: JSON.stringify({
payload: {
source: "TELEMETRY",
activity_type: "COPILOTKIT_EVENT",
event,
properties: orderedPropertiesWithGlobal,
}
})
});
} catch (error) {
// Silently fail - telemetry errors should not impact application
}
🤖 Prompt for AI Agents
In CopilotKit/packages/shared/src/telemetry/telemetry-client.ts around lines 103
to 118, the fetch to the Reo ingest endpoint has no error handling and can cause
unhandled rejections or throw on non-2xx responses; wrap the fetch call in a
try/catch, await it inside the try, check the response.ok and handle non-OK
responses (log them) and swallow any network or JSON errors in the catch so the
capture method never throws; optionally set a short timeout/AbortSignal for the
request and log any errors for telemetry debugging without rethrowing or
impacting the main flow.

});

const reoUrl = "https://ingest.reo.dev/api/product/usage"
await fetch(reoUrl, {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Major: Add timeout to prevent indefinite hanging.

The fetch request has no timeout configured. If the Reo endpoint is slow or unresponsive, this will block the telemetry capture method indefinitely, potentially impacting application performance. External calls should always have timeouts.

Consider adding an AbortController with timeout:

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout

try {
  await fetch(reoUrl, {
    method: "POST",
    signal: controller.signal,
    headers: {
      "Content-Type": "application/json",
      "X-API-KEY": process.env.NEXT_PUBLIC_REO_KEY || "",
    },
    body: JSON.stringify({
      payload: {
        source: "TELEMETRY",
        activity_type: "COPILOTKIT_EVENT",
        event,
        properties: orderedPropertiesWithGlobal,
      }
    })
  });
} catch (error) {
  // Silently fail - telemetry errors should not impact application
} finally {
  clearTimeout(timeoutId);
}
🤖 Prompt for AI Agents
In CopilotKit/packages/shared/src/telemetry/telemetry-client.ts around line 104,
the fetch call has no timeout and can hang indefinitely; add an AbortController,
start a timeout (e.g. 5000 ms) that calls controller.abort(), pass
controller.signal into fetch options, wrap the fetch in try/catch/finally to
silently swallow errors (so telemetry failures don't affect app), and clear the
timeout in finally to avoid leaks.

method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": process.env.NEXT_PUBLIC_REO_KEY || "",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n "CopilotKit/packages/shared/src/telemetry/telemetry-client.ts" | head -130 | tail -30

Repository: CopilotKit/CopilotKit

Length of output: 1106


🏁 Script executed:

#!/bin/bash
# Check the file around line 108
echo "=== File content around line 108 ==="
cat -n "CopilotKit/packages/shared/src/telemetry/telemetry-client.ts" | sed -n '100,120p'

# Find all usages of REO_KEY
echo -e "\n=== All usages of REO_KEY ==="
rg "REO_KEY" --type ts --type tsx

# Check if telemetry-client is used client-side
echo -e "\n=== Imports of telemetry-client ==="
rg "telemetry-client" --type ts --type tsx | head -20

Repository: CopilotKit/CopilotKit

Length of output: 875


🏁 Script executed:

#!/bin/bash
# Try different search patterns for REO usage
echo "=== Search for NEXT_PUBLIC_REO ==="
rg "NEXT_PUBLIC_REO" 

echo -e "\n=== Search for telemetry-client imports ==="
rg "from.*telemetry-client|import.*telemetry-client"

echo -e "\n=== Check if telemetry-client is exported from index ==="
find . -name "index.ts" -o -name "index.tsx" | xargs grep -l "telemetry-client" 2>/dev/null | head -10

echo -e "\n=== Check the file type of telemetry-client.ts ==="
file "CopilotKit/packages/shared/src/telemetry/telemetry-client.ts"

echo -e "\n=== List files in telemetry directory ==="
ls -la "CopilotKit/packages/shared/src/telemetry/"

Repository: CopilotKit/CopilotKit

Length of output: 2710


🏁 Script executed:

#!/bin/bash
# Check the full telemetry-client.ts to understand its execution context
echo "=== Full telemetry-client.ts content ==="
cat "CopilotKit/packages/shared/src/telemetry/telemetry-client.ts"

echo -e "\n=== Check docs/app/layout.tsx usage ==="
grep -A 5 -B 5 "NEXT_PUBLIC_REO_KEY" "docs/app/layout.tsx"

echo -e "\n=== Check if telemetry-client is used in browser/client context ==="
rg -B 5 -A 5 "telemetry-client|telemetry\." "CopilotKit/packages/shared/src/telemetry/index.ts"

Repository: CopilotKit/CopilotKit

Length of output: 5182


🏁 Script executed:

#!/bin/bash
# Check if telemetry-client is actually bundled and sent to client
echo "=== Check package.json to see if shared is exported to browser ==="
cat "CopilotKit/packages/shared/package.json" | grep -A 10 "exports\|main"

# Check if TelemetryClient is used in browser components
echo -e "\n=== Search for TelemetryClient usage in UI/browser context ==="
rg "TelemetryClient|telemetry\.capture" "CopilotKit/packages/react" | head -20

# Check the actual runtime where telemetry-client is used
echo -e "\n=== Check if capture method is called from server or client contexts ==="
rg -B 3 "\.capture\(" "CopilotKit/packages/runtime/src" | head -40

Repository: CopilotKit/CopilotKit

Length of output: 4128


🏁 Script executed:

#!/bin/bash
# Let's check the docs/app/layout.tsx more carefully to see if REO_KEY is used client-side
echo "=== Full context around REO_KEY in docs/app/layout.tsx ==="
grep -n "NEXT_PUBLIC_REO_KEY" "docs/app/layout.tsx" -B 10 -A 10

# Check if docs is using this as a client component
echo -e "\n=== Check if docs/app/layout.tsx is a server or client component ==="
head -30 "docs/app/layout.tsx"

# Check what REO_KEY is used for in the docs
echo -e "\n=== Search for usage of REO_KEY variable in docs/app/layout.tsx ==="
grep -n "REO_KEY" "docs/app/layout.tsx"

Repository: CopilotKit/CopilotKit

Length of output: 2170


🏁 Script executed:

#!/bin/bash
# Check the complete context of REO_KEY usage in docs/app/layout.tsx
echo "=== Full REO_KEY usage section in docs/app/layout.tsx ==="
sed -n '13,50p' "docs/app/layout.tsx"

# Verify where telemetry-client.ts is actually executed
echo -e "\n=== Check which packages/runtime modules are server-side only ==="
grep -r "\"server-only\"" "CopilotKit/packages/runtime/src" | head -5

# Check if telemetry-client.ts has any "use client" or server context indication
echo -e "\n=== Check telemetry-client.ts for execution context markers ==="
head -10 "CopilotKit/packages/shared/src/telemetry/telemetry-client.ts"

Repository: CopilotKit/CopilotKit

Length of output: 2025


Remove NEXT_PUBLIC_ prefix or clarify that the REO key is a public client ID.

The NEXT_PUBLIC_REO_KEY variable is used in server-side telemetry code, but the NEXT_PUBLIC_ prefix is only necessary when variables need to be exposed to the browser. Since telemetry-client.ts runs exclusively on the server (in runtime packages), the prefix is redundant. However, this is not a security issue—the key is a public client ID for Reo's analytics service and is intentionally used client-side in docs/app/layout.tsx. Consider either:

  1. Renaming to REO_CLIENT_ID in telemetry-client.ts (server-only usage), keeping NEXT_PUBLIC_REO_KEY in docs for client-side initialization
  2. Documenting why NEXT_PUBLIC_ is used if sharing the same variable is preferred
🤖 Prompt for AI Agents
In CopilotKit/packages/shared/src/telemetry/telemetry-client.ts around line 108,
the code uses process.env.NEXT_PUBLIC_REO_KEY in server-side telemetry; remove
the unnecessary NEXT_PUBLIC_ prefix by switching to process.env.REO_CLIENT_ID
(server-only) and update any config/CI/env docs accordingly; to avoid breaking
existing deployments, read REO_CLIENT_ID first and fall back to
NEXT_PUBLIC_REO_KEY if REO_CLIENT_ID is undefined, and update comments to state
that the REO value is a public client ID used client-side in
docs/app/layout.tsx.

@changesets-bot-copilotkit
Copy link

⚠️ No Changeset found

Latest commit: 66e5f1a

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here if you're a maintainer who wants to add a changeset to this PR

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants