Back to Copilotkit

Writing agent state

docs/content/docs/integrations/microsoft-agent-framework/shared-state/in-app-agent-write.mdx

1.57.18.2 KB
Original Source

import RunAndConnect from "@/snippets/integrations/microsoft-agent-framework/run-and-connect.mdx" import { IframeSwitcher } from "@/components/content" <IframeSwitcher id="shared-state-example" exampleUrl="https://feature-viewer.copilotkit.ai/microsoft-agent-framework-dotnet/feature/shared_state?sidebar=false&chatDefaultOpen=false" codeUrl="https://feature-viewer.copilotkit.ai/microsoft-agent-framework-dotnet/feature/shared_state?view=code&sidebar=false&codeLayout=tabs" exampleLabel="Demo" codeLabel="Code" height="700px" />

<Callout type="info"> This example demonstrates reading from shared state in the [CopilotKit Feature Viewer](https://feature-viewer.copilotkit.ai/microsoft-agent-framework-dotnet/feature/shared_state). </Callout>

What is this?

This guide shows you how to write to your agent's state from your application.

When should I use this?

You can use this when you need to update agent state from your application — for example, changing user preferences, toggling settings, or providing user input that affects agent behavior.

Implementation

<Steps> <Step> ### Run and connect your agent <RunAndConnect components={props.components} /> </Step> <Step> ### Define the Agent State Decide which parts of agent state you want to reflect in the UI and allow updating from the UI.
<Tabs groupId="language_microsoft-agent-framework_agent" items={['.NET', 'Python']} persist>
  <Tab value=".NET">
    ```csharp title="agent/Program.cs (excerpt)"
    public class AgentStateSnapshot
    {
        public string Language { get; set; } = "english";
    }
    ```
  </Tab>
  <Tab value="Python">
    ```python title="main.py"
    from __future__ import annotations
    import os
    import uvicorn
    from agent_framework import Agent, tool, SupportsChatGetResponse
    from agent_framework.openai import OpenAIChatClient
    from agent_framework.ag_ui import add_agent_framework_fastapi_endpoint
    from agent_framework.ag_ui import AgentFrameworkAgent
    from dotenv import load_dotenv
    from fastapi import FastAPI
    from typing import Annotated
    from pydantic import BaseModel, Field

    load_dotenv()

    class SearchItem(BaseModel):
        query: str
        done: bool
        
    STATE_SCHEMA: dict[str, object] = {
        "language": {
            "type": "string",
            "enum": ["english", "spanish"],
            "description": "Preferred language.",
        }
    }
    PREDICT_STATE_CONFIG: dict[str, dict[str, str]] = {
        "language": {"tool": "update_language", "tool_argument": "language"}
    }

    @tool
    def update_language(
        language: Annotated[str, Field(description="Preferred language: 'english' or 'spanish'")],
    ) -> str:
        normalized = (language or "").strip().lower()
        if normalized not in ("english", "spanish"):
            return "Language unchanged. Use 'english' or 'spanish'."
        return f"Language updated to {normalized}."


    def _build_chat_client():
        if os.getenv("AZURE_OPENAI_ENDPOINT"):
            return OpenAIChatClient(
                model=os.getenv("AZURE_OPENAI_CHAT_DEPLOYMENT_NAME", "gpt-4o-mini"),
                api_key=os.getenv("AZURE_OPENAI_API_KEY"),
                azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
            )
        if os.getenv("OPENAI_API_KEY"):
            return OpenAIChatClient(
                model=os.getenv("OPENAI_CHAT_MODEL_ID", "gpt-4o-mini"),
                api_key=os.getenv("OPENAI_API_KEY"),
            )
        raise RuntimeError(
            "Set either AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_API_KEY, or OPENAI_API_KEY."
        )



    def create_agent(chat_client: SupportsChatGetResponse) -> AgentFrameworkAgent:
        base_agent = Agent(
            name="sample_agent",
            instructions="You are a helpful assistant.",
            client=chat_client,
            tools=[update_language],   
        )
        return AgentFrameworkAgent(
            agent=base_agent,
            name="CopilotKitMicrosoftAgentFrameworkAgent",
            description="Assistant that tracks a simple language state.",
            state_schema=STATE_SCHEMA,               
            predict_state_config=PREDICT_STATE_CONFIG, 
            require_confirmation=False,
        )
        

    chat_client = _build_chat_client()

    agent = create_agent(chat_client)

    app = FastAPI(title="Microsoft Agent Framework - Quickstart")
    add_agent_framework_fastapi_endpoint(app=app, agent=agent, path="/")

    if __name__ == "__main__":
        uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
    ```
  </Tab>
</Tabs>

```ts title="ui/app/page.tsx"
type AgentState = {
  language: "english" | "spanish";
}
```
</Step> <Step> ### Call `agent.setState` from the `useAgent` hook `useAgent` returns an `agent` object with a `setState` method that you can use to update the agent state. Calling this will update the agent state and trigger a rerender of anything that depends on the agent state.
```tsx title="ui/app/page.tsx"
import { useAgent } from "@copilotkit/react-core/v2"; // [!code highlight]

// Define the agent state type, should match the actual state of your agent
type AgentState = {
  language: "english" | "spanish";
}

// Example usage in a pseudo React component
function YourMainContent() {
  const { agent } = useAgent({ // [!code highlight]
    agentId: "sample_agent",
    initialState: { language: "english" }  // optionally provide an initial state
  });

  // ...

  const toggleLanguage = () => {
    agent.setState({ language: agent.state?.language === "english" ? "spanish" : "english" }); // [!code highlight]
  };

  // ...

  return (
    // style excluded for brevity
    <div>
      <h1>Your main content</h1>
      <p>Language: {agent.state?.language}</p>
      <button onClick={toggleLanguage}>Toggle Language</button>
    </div>
  );
}
```
</Step> <Step> ### Give it a try! You can now use `agent.setState` to update the agent state and `agent.state` to read it. Try toggling the language button and talking to your agent. You'll see the language change to match the agent's state. <video src="https://cdn.copilotkit.ai/docs/copilotkit/images/coagents/write-agent-state.mp4" className="rounded-lg shadow-xl" loop playsInline controls autoPlay muted /> <Callout> This video shows the result of `npx copilotkit@latest init` with the implementation section applied to it! </Callout> </Step> </Steps>

Advanced Usage

Re-run the agent with a hint about what's changed

The new agent state will be used next time the agent runs. If you want to re-run it manually, use copilotkit.runAgent().

The agent will be re-run with the latest updated state. You can also add a hint message before re-running.

tsx
import { useAgent, useCopilotKit } from "@copilotkit/react-core/v2";

// ...

function YourMainContent() {
  const { agent } = useAgent({
    agentId: "sample_agent",
  });
  const { copilotkit } = useCopilotKit(); // [!code highlight]

  // setup to be called when some event in the app occurs
  const toggleLanguage = async () => {
    const newLanguage = agent.state?.language === "english" ? "spanish" : "english";
    agent.setState({ language: newLanguage });

    // add a hint message and re-run the agent
    // [!code highlight:7]
    agent.addMessage({
      id: crypto.randomUUID(),
      role: "user",
      content: `the language has been updated to ${newLanguage}`,
    });
    await copilotkit.runAgent({ agent });
  };

  return (
    // ...
  );
}

Notes on state updates

Depending on your agent implementation, you may choose to surface progress via tool responses or messages rather than frequent state snapshots. See Generative UI for recommended patterns.