CopilotKit

Agent Config

Forward typed configuration from your UI into the agent's reasoning loop.


"use client";import { CopilotKitProvider, CopilotChat } from "@copilotkit/react-core/v2";import { useMemo } from "react";import { ConfigCard } from "./config-card";import { useAgentConfig } from "./use-agent-config";export default function AgentConfigDemoPage() {  const { config, setTone, setExpertise, setResponseLength } = useAgentConfig();  // Stable reference between renders when nothing has changed so the  // provider's `[properties]`-keyed effect only re-fires on real updates.  const providerProperties = useMemo<Record<string, unknown>>(    () => ({      tone: config.tone,      expertise: config.expertise,      responseLength: config.responseLength,    }),    [config.tone, config.expertise, config.responseLength],  );  return (    <CopilotKitProvider      runtimeUrl="/api/copilotkit-agent-config"      properties={providerProperties}      useSingleEndpoint    >      <div className="flex h-screen flex-col gap-3 p-6">        <header>          <h1 className="text-lg font-semibold">Agent Config Object</h1>          <p className="text-sm text-neutral-600">            Forwarded props let the frontend tell the agent how to behave. This            demo passes <code>tone</code>, <code>expertise</code>, and            <code> responseLength</code> through the provider; the            built-in-agent factory reads them from{" "}            <code>input.forwardedProps</code> and prepends a tuned system prompt            per turn.          </p>        </header>        <ConfigCard          config={config}          onToneChange={setTone}          onExpertiseChange={setExpertise}          onResponseLengthChange={setResponseLength}        />        <div className="flex-1 overflow-hidden rounded-md border border-neutral-200">          <CopilotChat className="h-full rounded-md" />        </div>      </div>    </CopilotKitProvider>  );}

You have a working agent and want the user to be able to tune how it behaves: tone, expertise level, response length, language, persona. By the end of this guide, your UI will own a typed config object that the agent reads on every run and rebuilds its system prompt from.

When to use this#

Reach for agent config whenever the agent's behaviour depends on user-controllable settings that don't fit naturally as chat input:

  • Tone, voice, persona: "playful", "formal", "casual"
  • Expertise level: "beginner", "intermediate", "expert"
  • Response shape: short / medium / long, structured / prose, language
  • Domain switches: which knowledge base to consult, which tool subset to enable

If the values are a channel the user occasionally tunes (a settings panel, a toolbar of selects), agent config is the right shape. If the values are content the agent should write back to (notes, a document, a plan), use Shared State instead.

How agent config flows from the UI into the agent's reasoning loop depends on your runtime architecture. Agents living behind a runtime read it from agent state on every run, while in-process agents receive the same object as forwarded properties on the provider — same UX, slightly different wiring on each side.

How it works#

The runtime owns the agent in-process, so config travels through the provider rather than agent state. There's no separate backend service to push state into, and no extra plumbing — the typed object you set on <CopilotKit> becomes the input to the agent factory directly.

The UI side passes the typed object as properties on the provider:

frontend/src/app/page.tsx — config flows through the provider
<CopilotKit
  runtimeUrl="/api/copilotkit"
  properties={{ tone, expertise, responseLength }}
  useSingleEndpoint
>
  <Demo />
</CopilotKit>

The runtime hands the same object to the agent factory on every call as input.forwardedProps. The factory uses those fields to build a system prompt before returning the agent for that turn:

backend/agent factory — synthesise the system prompt per turn
export const agentConfigFactory = async (input: AgentFactoryInput) => {
  const { tone, expertise, responseLength } = input.forwardedProps ?? {};
  const systemPrompt = buildSystemPrompt(tone, expertise, responseLength);
  return makeAgent({ systemPrompt /* ... */ });
};