Skip to content
Merged
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
46 changes: 46 additions & 0 deletions docs/snippets/shared/premium/self-hosting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ CopilotKit Intelligence — the platform that powers threads, shared state, the

Plus a `database-migrations` Job, a `thread-culler` CronJob, and the usual supporting resources (Services, Ingress, HPAs, PodDisruptionBudgets, ConfigMaps, and — when ESO is enabled — ExternalSecret resources).

<Callout type="info" title="User memory (closed beta)">
The Intelligence Platform image also includes an opt-in user memory
capability: agents can recall information from prior conversations in the
same project (e.g. *"what did we discuss earlier?"*, *"remind me about X"*).
Currently supported with the Built-in Agent runtime. Reach out to your
CopilotKit contact for access; see [Configuration reference → User memory](#user-memory-closed-beta) below for the enablement variables.
</Callout>

## When should I use this?

- Your organization requires CopilotKit Intelligence to run inside your own VPC or data center for compliance, data residency, or security reasons
Expand Down Expand Up @@ -474,6 +482,44 @@ The tables below summarize the most common values. For every option, see `values

Enabling the realtime gateway requires that either `realtimeGateway.existingSecret` is set, or that `externalSecrets.secrets.realtimeGateway.enabled` or `selfHostedSecrets.enabled` is `true` — the chart fails validation otherwise.

### User memory (closed beta)

<InsecurePasswordProtected password="cpki-mem-beta">

User memory lets agents recall information from prior conversations in the same project. Built-in Agent runtime only today; LangGraph, Mastra, and other frameworks are in development.

**What it does.** The chat agent can recall the user's prior conversations and use that recall to answer questions like:

- *"What did we discuss last week?"*
- *"Remind me what I decided about X"*
- *"Have we covered Y before?"*

**Scope.** Only the current user's conversations in the current `(organization, project)`. The agent never sees another user's conversations or another project's data, and it cannot modify what was said.

**Discovery.** The agent will use the capability on its own when asked recall-style questions; for best results, add one line to your agent's `prompt` nudging it to consult its memory when relevant.

**Enabling it.** Two flips, one on each side:

| Where | How |
|---|---|
| `app-api` (platform) | Set `SL_ENABLED=true` via `appApi.env: [{ name: SL_ENABLED, value: "true" }]` in your `values.yaml`. This mounts the platform's `/mcp` endpoint on `app-api`. |
| Your runtime / BFF | Pass `mcpServer: true` when constructing `CopilotKitIntelligence` from `@copilotkit/runtime/v2`. The runtime then auto-attaches the platform's `/mcp` endpoint to every `BuiltInAgent` run. |

```typescript title="runtime.ts"
import { CopilotKitIntelligence } from "@copilotkit/runtime/v2";

const intelligence = new CopilotKitIntelligence({
apiKey: process.env.INTELLIGENCE_API_KEY!,
apiUrl: process.env.INTELLIGENCE_API_URL!,
wsUrl: process.env.INTELLIGENCE_GATEWAY_WS_URL!,
mcpServer: true, // [!code highlight]
});
```

Once both flips are in place the agent gains recall on its next turn — no further application changes needed.

</InsecurePasswordProtected>

### External Secrets Operator integration

| Key | Description | Default |
Expand Down
2 changes: 1 addition & 1 deletion packages/a2ui-renderer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/a2ui-renderer",
"version": "1.57.3",
"version": "1.57.4",
"private": false,
"description": "A2UI Renderer for CopilotKit - render A2UI surfaces in React applications",
"keywords": [
Expand Down
2 changes: 1 addition & 1 deletion packages/agentcore-runner/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/agentcore-runner",
"version": "1.57.3",
"version": "1.57.4",
"description": "AWS Bedrock AgentCore-compatible agent runner for CopilotKit2",
"type": "module",
"main": "./dist/index.cjs",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/core",
"version": "1.57.3",
"version": "1.57.4",
"description": "Core web utilities for CopilotKit2",
"type": "module",
"main": "./dist/index.cjs",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/react-core",
"version": "1.57.3",
"version": "1.57.4",
"private": false,
"keywords": [
"ai",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-native/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/react-native",
"version": "1.57.3",
"version": "1.57.4",
"private": false,
"keywords": [
"ai",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-textarea/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/react-textarea",
"version": "1.57.3",
"version": "1.57.4",
"private": false,
"keywords": [
"ai",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/react-ui",
"version": "1.57.3",
"version": "1.57.4",
"private": false,
"keywords": [
"ai",
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime-client-gql/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/runtime-client-gql",
"version": "1.57.3",
"version": "1.57.4",
"private": false,
"keywords": [
"ai",
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/runtime",
"version": "1.57.3",
"version": "1.57.4",
"private": false,
"keywords": [
"ai",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import { describe, it, expect } from "vitest";
import { configureAgentForRequest } from "../handlers/shared/agent-utils";
import type { AbstractAgent } from "@ag-ui/client";
import type { CopilotRuntimeLike } from "../core/runtime";

/**
* Minimal agent stub that satisfies the MiddlewareCapableAgent shape
* used inside configureAgentForRequest.
*/
function createMockAgent(headers?: Record<string, string>): AbstractAgent {
return {
headers,
// configureAgentForRequest checks `typeof agent.use === "function"`
use: () => {},
} as unknown as AbstractAgent;
}

function createMockRuntime(): CopilotRuntimeLike {
return {
agents: Promise.resolve({}),
} as unknown as CopilotRuntimeLike;
}

function createRequest(headers: Record<string, string>): Request {
return new Request("https://example.com/agent/test-agent/run", {
method: "POST",
headers,
});
}

describe("configureAgentForRequest – header forwarding", () => {
it("forwards x-aimock-context when agent.headers is undefined (default LangGraphAgent)", () => {
const agent = createMockAgent(/* headers = undefined */);
const request = createRequest({
"Content-Type": "application/json",
"x-aimock-context": "langgraph-python",
});

configureAgentForRequest({
runtime: createMockRuntime(),
request,
agentId: "test-agent",
agent,
});

// The core regression: before the fix, agent.headers stayed undefined
// because the old `if (agent.headers)` guard skipped the assignment.
expect((agent as any).headers).toBeDefined();
expect((agent as any).headers["x-aimock-context"]).toBe("langgraph-python");
});

it("forwards x-test-id when agent.headers is undefined", () => {
const agent = createMockAgent();
const request = createRequest({
"Content-Type": "application/json",
"x-test-id": "run-42",
});

configureAgentForRequest({
runtime: createMockRuntime(),
request,
agentId: "test-agent",
agent,
});

expect((agent as any).headers["x-test-id"]).toBe("run-42");
});

it("merges forwardable headers with pre-existing agent.headers", () => {
const agent = createMockAgent({
"x-existing": "keep-me",
authorization: "Bearer original-token",
});
const request = createRequest({
"Content-Type": "application/json",
"x-aimock-context": "langgraph-python",
"x-test-id": "run-99",
});

configureAgentForRequest({
runtime: createMockRuntime(),
request,
agentId: "test-agent",
agent,
});

const headers = (agent as any).headers as Record<string, string>;

// Pre-existing headers preserved
expect(headers["x-existing"]).toBe("keep-me");
expect(headers["authorization"]).toBe("Bearer original-token");

// Forwardable headers merged in
expect(headers["x-aimock-context"]).toBe("langgraph-python");
expect(headers["x-test-id"]).toBe("run-99");
});

it("request forwardable headers override matching pre-existing agent headers", () => {
const agent = createMockAgent({
"x-aimock-context": "old-context",
});
const request = createRequest({
"x-aimock-context": "new-context",
});

configureAgentForRequest({
runtime: createMockRuntime(),
request,
agentId: "test-agent",
agent,
});

// The spread order is { ...agent.headers, ...extracted } so request wins
expect((agent as any).headers["x-aimock-context"]).toBe("new-context");
});

it("does NOT forward non-forwardable headers like content-type or origin", () => {
const agent = createMockAgent();
const request = createRequest({
"Content-Type": "application/json",
Origin: "http://localhost:3000",
"User-Agent": "test-runner",
Cookie: "session=abc",
Host: "example.com",
Accept: "text/event-stream",
// Only this one should come through
"x-aimock-context": "langgraph-python",
});

configureAgentForRequest({
runtime: createMockRuntime(),
request,
agentId: "test-agent",
agent,
});

const headers = (agent as any).headers as Record<string, string>;

// Non-forwardable headers must NOT be present
expect(headers["content-type"]).toBeUndefined();
expect(headers["origin"]).toBeUndefined();
expect(headers["user-agent"]).toBeUndefined();
expect(headers["cookie"]).toBeUndefined();
expect(headers["host"]).toBeUndefined();
expect(headers["accept"]).toBeUndefined();

// The x- header IS forwarded
expect(headers["x-aimock-context"]).toBe("langgraph-python");
});

it("authorization header IS forwarded (it is in the allowlist)", () => {
const agent = createMockAgent();
const request = createRequest({
Authorization: "Bearer secret-token",
"Content-Type": "application/json",
});

configureAgentForRequest({
runtime: createMockRuntime(),
request,
agentId: "test-agent",
agent,
});

const headers = (agent as any).headers as Record<string, string>;
expect(headers["authorization"]).toBe("Bearer secret-token");
expect(headers["content-type"]).toBeUndefined();
});

it("results in empty headers object when request has no forwardable headers and agent.headers is undefined", () => {
const agent = createMockAgent();
const request = createRequest({
"Content-Type": "application/json",
Origin: "http://localhost",
});

configureAgentForRequest({
runtime: createMockRuntime(),
request,
agentId: "test-agent",
agent,
});

// Even with no forwardable headers, agent.headers should be set (not undefined)
expect((agent as any).headers).toBeDefined();
expect((agent as any).headers).toEqual({});
});
});
10 changes: 4 additions & 6 deletions packages/runtime/src/v2/runtime/handlers/shared/agent-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,10 @@ export function configureAgentForRequest(params: {
}
}

if (agent.headers) {
agent.headers = {
...agent.headers,
...extractForwardableHeaders(request),
};
}
agent.headers = {
...agent.headers,
...extractForwardableHeaders(request),
};
}

export async function parseRunRequest(
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/sdk-js",
"version": "1.57.3",
"version": "1.57.4",
"private": false,
"keywords": [
"ai",
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/shared",
"version": "1.57.3",
"version": "1.57.4",
"private": false,
"keywords": [
"ai",
Expand Down
2 changes: 1 addition & 1 deletion packages/sqlite-runner/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/sqlite-runner",
"version": "1.57.3",
"version": "1.57.4",
"description": "SQLite-backed agent runner for CopilotKit2",
"type": "module",
"main": "./dist/index.cjs",
Expand Down
2 changes: 1 addition & 1 deletion packages/voice/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/voice",
"version": "1.57.3",
"version": "1.57.4",
"description": "Voice services for CopilotKit (transcription, text-to-speech, etc.)",
"type": "module",
"main": "./dist/index.cjs",
Expand Down
2 changes: 1 addition & 1 deletion packages/vue/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/vue",
"version": "1.57.3",
"version": "1.57.4",
"private": false,
"description": "Vue 3 components and composables for CopilotKit",
"keywords": [
Expand Down
2 changes: 1 addition & 1 deletion packages/web-inspector/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@copilotkit/web-inspector",
"version": "1.57.3",
"version": "1.57.4",
"description": "Lit-based web component for the CopilotKit web inspector",
"type": "module",
"main": "./dist/index.cjs",
Expand Down
Loading
Loading