From 25b518108841bbcf79d39aadc363400a2f0b2fdc Mon Sep 17 00:00:00 2001 From: Atai Barkai Date: Thu, 17 Oct 2024 01:29:37 -0700 Subject: [PATCH] getting started --- .../react/coagents/coagents-diagram.tsx | 44 +++ .../content/docs/coagents/getting-started.mdx | 287 ++++-------------- docs/content/docs/coagents/index.mdx | 190 +----------- 3 files changed, 107 insertions(+), 414 deletions(-) create mode 100644 docs/components/react/coagents/coagents-diagram.tsx diff --git a/docs/components/react/coagents/coagents-diagram.tsx b/docs/components/react/coagents/coagents-diagram.tsx new file mode 100644 index 0000000000..0c675ba392 --- /dev/null +++ b/docs/components/react/coagents/coagents-diagram.tsx @@ -0,0 +1,44 @@ +import React from "react"; + +export const CoAgentsDiagram: React.FC = (): JSX.Element => { + return ( +
+
+ + + + + + + +
+
+ ); +}; + +interface DiagramNodeProps { + title: string; +} + +const DiagramNode: React.FC = ({ title }): JSX.Element => { + return ( +
+ {title} +
+ ); +}; + +const DiagramArrow: React.FC = (): JSX.Element => { + return ( +
+ + + +
+ ); +}; \ No newline at end of file diff --git a/docs/content/docs/coagents/getting-started.mdx b/docs/content/docs/coagents/getting-started.mdx index a65a84d9cf..225b861e6f 100644 --- a/docs/content/docs/coagents/getting-started.mdx +++ b/docs/content/docs/coagents/getting-started.mdx @@ -5,271 +5,102 @@ description: "Get started with CoAgents in just a few minutes." import { CoAgentsEnterpriseCTA } from "@/components/react/coagents/coagents-enterprise-cta.tsx"; import SelfHostingCopilotRuntimeCreateEndpoint from "@/snippets/self-hosting-copilot-runtime-create-endpoint.mdx"; import LLMAdapters from "@/snippets/llm-adapters.mdx"; +import { CoAgentsDiagram } from "@/components/react/coagents/coagents-diagram.tsx"; + ## Before you start -These docs assume you’ve been introduced to CopilotKit’s core concepts and components. If you’re new to CopilotKit, take a minute to go through the quickstart and [learn how to integrate CopilotKit into a React app](/quickstart). +At the moment CoAgents integrates with LangGraph-powered agents using **LangGraph-Python**.
+(Support for LangGraph.js and LangGraph Cloud is coming soon!) -Also, at the moment CoAgents integrates with LangGraph-powered agents using their Python SDK. (Support for LangGraph JS and LangGraph Cloud are coming soon!) +**For orientation, here's how CoAgents are wired:** + + + + + This guide assumes you’re familiar with using LangGraph to build agent workflows. If you need a quick introduction, check out [this brief example from the LangGraph docs](https://docs.langgraph.ai/quickstart). + + + + + + +## Getting started + + +First, take a minute to **[go through the CopilotKit quickstart](/quickstart), and integrate CopilotKit into your React app.** +This should only take a minute. + + + + +Then, setup a CopilotKit Remote-Endpoint using FastAPI. This endpoint will serve your LangGraph agent. +Follow the [Remote Endpoint quickstart](/guides/backend-actions/remote-backend-endpoint). + -## Setup a remote endpoint in Python + FastAPI -CoAgents require you to use a remote endpoint using Python, FastAPI, and the CopilotKit Python SDK; here's a basic example to get you started. +## Connect your FastAPI Remote Endpoint to a LangGraph agent - -If you're starting from scratch or need more information, check out our [remote endpoint docs](/guides/backend-actions/remote-backend-endpoint) for a complete walkthrough. - -In your Python project, install the CopilotKit SDK: +At this point you should have CopilotKit hooked into your application, connected to a FastAPI Remote Endpoint. -```bash -pip install copilotkit --extra-index-url https://copilotkit.gateway.scarf.sh/simple/ -``` +The next step is to configure the Remote Endpoint to serve LangGraph agents. -Then set up or update your FastAPI server to initialize our SDK and connect it to your LangGraph agent. In this example, we’re assuming a basic agent workflow is being exported from `agent.py` in the same directory as this server script. +**Modify your server.py file (setup in step (2)) to serve LangGraph agents:** -```python filename="server.py" showLineNumbers +```python title="server.py" from fastapi import FastAPI -app = FastAPI() - -# Import CopilotKit SDK and integrations from copilotkit.integrations.fastapi import add_fastapi_endpoint from copilotkit import CopilotKitSDK, LangGraphAgent - + +app = FastAPI() + # Import your LangGraph agent; in this example, it's the variable # named `basic_agent_graph` in ./agent.py from .agent import basic_agent_graph - + # Initialize the agent for use by CopilotKit; we'll name it "basic_agent" -basic_agent = LangGraphAgent( +basic_agent = LangGraphAgent( // [!code highlight:4] name="basic_agent", description="Agent that asks about the weather", agent=basic_agent_graph, ) - -# Next, initialize the SDK, passing in the agent -sdk = CopilotKitSDK( - agents=[ - basic_agent - ], -) - -# Finally, add the remote actions endpoint to this API -add_fastapi_endpoint(app, sdk, "/copilotkit_remote") -``` +# Initialize the CopilotKit SDK +sdk = CopilotKitSDK(agents=[basic_agent]) [!code highlight:1] + +# Add the CopilotKit endpoint to your FastAPI app +add_fastapi_endpoint(app, sdk, "/copilotkit_remote") + +def main(): + """Run the uvicorn server.""" + import uvicorn + uvicorn.run("server:app", host="127.0.0.1", port=8000, reload=True) + +``` Remember the name `basic_agent` as well as our API endpoint URL (`http://localhost:8000/copilotkit_remote`), we'll need them as we move on to integrating this agent into the frontend. - -## Self-host the Copilot Runtime - -To use your remote agent service, you’ll also need to self-host the CopilotRuntime service. (Support for CopilotCloud is coming soon.) - -### Configure an AI service adapter - -First, we’ll create a new module file to initialize a runtime adapter for our LLM of choice, which we’ll put at `src/lib/serviceAdapter.ts`. - - - - - - -Create a `.env` file in the root of your project, if you haven't already, and add your OpenAI API key. - -```plaintext filename=".env" -OPENAI_API_KEY=your_api_key_here -``` - - - Please note that the code below uses GPT-4o, which requires a paid OpenAI API key. - **If you are using a free OpenAI API key**, change the model to a different option such as "gpt-3.5-turbo". - - -Then create a new file called `src/lib/llmAdapter.ts`: - -```ts filename="src/lib/llmAdapter.ts" -import OpenAI from 'openai'; -import { OpenAIAdapter } from '@copilotkit/runtime'; - -const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); - -const openaiAdapter = new OpenAIAdapter({ - openai, - model: "gpt-4o" -}); - -export default openaiAdapter -``` - - - -Create a `.env` file in the root of your project, if you haven't already, and add your Anthropic API key. - -```plaintext filename=".env" -ANTHROPIC_API_KEY=your_api_key_here -``` - -Then create a new file called `src/lib/llmAdapter.ts`: - -```ts filename="src/lib/llmAdapter.ts" -import Anthropic from '@anthropic-ai/sdk'; -import { AnthropicAdapter } from '@copilotkit/runtime'; - -const anthropic = new Anthropic({ - apiKey: 'my_api_key', // defaults to process.env["ANTHROPIC_API_KEY"] -}); - -const anthropicAdapter = new AnthropicAdapter({ anthropic }); - -export default anthropicAdapter -``` - - - - To use a different LLM provider, you can follow the `OpenAI` instructions, but adapt them to use one of the other available LLM adapters listed below: - - - - - - -### Add a CopilotRuntime endpoint to your app - -Next, you'll use the service adapter you created above to initialize a `CopilotRuntime` instance and add a new route to your app. Here are some examples for the most common Node server frameworks: - - - - {/* Next.js App Router */} - - Next, create a new server route which will make the `CopilotRuntime` available at `/api/copilotkit` and ready to work with remote actions provided by our Python app. - - Create a new file at `src/app/api/copilotkit/route.ts` and add this code: - - ```ts filename="app/api/copilotkit/route.ts" showLineNumbers - import { - CopilotRuntime, - copilotRuntimeNextJSAppRouterEndpoint, - } from '@copilotkit/runtime'; - import { NextRequest } from 'next/server'; - import serviceAdapter from '@/lib/llmAdapter'; - - const runtime = new CopilotRuntime({ - remoteActions: [ - { - url: `http://localhost:8000/copilotkit_remote`, - } - ] - }); - - export const POST = async (req: NextRequest) => { - const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({ - runtime, - serviceAdapter, - endpoint: '/api/copilotkit', - }); - - return handleRequest(req); - }; - ``` - - - {/* Next.js Pages Router */} - - Next, create a new server route which will make the `CopilotRuntime` available at `/api/copilotkit` and ready to work with remote actions provided by our Python app. - - Create a new file at `src/pages/api/copilotkit.ts` and add this code: - - ```ts filename="pages/api/copilotkit.ts" showLineNumbers - import { NextApiRequest, NextApiResponse } from 'next'; - import { - CopilotRuntime, - copilotRuntimeNextJSPagesRouterEndpoint, - } from '@copilotkit/runtime'; - import serviceAdapter from '@/lib/llmAdapter'; - - const handler = async (req: NextApiRequest, res: NextApiResponse) => { - - const runtime = new CopilotRuntime({ - remoteActions: [ - { - url: `http://localhost:8000/copilotkit_remote`, - } - ] - }); - - const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({ - runtime, - serviceAdapter, - endpoint: '/api/copilotkit', - }); - - return await handleRequest(req, res); - }; - - export default handler; - ``` - - - {/* Node.js Express */} - - Next, create a new route handler which will make the `CopilotRuntime` available at `/copilotkit` and ready to work with remote actions provided by our Python app: - - ```ts filename="server.ts" showLineNumbers - import express from 'express'; - import { - CopilotRuntime, - copilotRuntimeNodeHttpEndpoint, - } from '@copilotkit/runtime'; - import llmAdapter from '@/lib/llmAdapter'; - - const app = express(); - - app.use('/copilotkit', (req, res, next) => { - - const runtime = new CopilotRuntime({ - remoteActions: [ - { - url: `http://localhost:8000/copilotkit_remote`, - } - ] - }); - - const handler = copilotRuntimeNodeHttpEndpoint({ - endpoint: '/copilotkit', - runtime, - serviceAdapter: llmAdapter, - }); - - return handler(req, res, next); - }); - - app.listen(4000, () => { - console.log('Listening at http://localhost:4000/copilotkit'); - }); - ``` - - - - - - -## Integrate agents into your CopilotKit frontend app +## Agent-lock your Copilot to the `base_agent` agent. -Once you've set up your agents, registered them with CopilotKit on the Python side, and mounted the CopilotRuntime within your app, all that's left is to hook this up to your frontend using the `` component. +CopilotKit supports router-mode as well as agent-lock mode. For more detail see [router-mode / agent-mode](/coagents/advanced/router-mode-agent-lock). + +For simplicity, wel'll use agent-lock mode in these tutorials, but in production use-cases you will likely want to use router-mode. + +Lock the Copilot to the `basic_agent` setup earlier. This means every single interaction with the Copilot will be forwarded to the locked agent. ```tsx filename="src/page.tsx" // This UI will now invoke our AI agent, not just the LLM @@ -283,13 +114,11 @@ Once you've set up your agents, registered them with CopilotKit on the Python si ``` -By passing in the `agent` prop, we're telling CopilotKit to go into "agent lock" mode, and only use the `basic_agent` we set up earlier. To customize this behavior, see our docs about [router mode](/coagents/advanced/router-mode-agent-lock). - -Any of CopilotKit's pre-built components can be used to interact with CoAgents, and you can also use agent-specific hooks in your custom UI components to enable powerful new workflows. - +🎉 Congrats! You've successfully integrated a LangGraph agent chatbot to your application! Give it a try now and see it in action. + diff --git a/docs/content/docs/coagents/index.mdx b/docs/content/docs/coagents/index.mdx index 1947b885c3..8fb95adf43 100644 --- a/docs/content/docs/coagents/index.mdx +++ b/docs/content/docs/coagents/index.mdx @@ -37,193 +37,13 @@ CopilotKit's CoAgents provides everything you need to deeply integrate LangGraph - - -## The Core Features of a CoAgent - - - - - - ### Generative UI - -Generative UI allows you to create dynamic user interfaces with AI-generated components, inside a chat UI. - -```tsx -useCoagentStateRender({ - // the name of the agent - name: "car_rental_agent", - - // this is optional: the node name to render generative UI for. If left empty, renders for every node. - nodeName: "confirm_node", - - // render can be a function or a string, just like useCopilotAction - render: ({ state, status }) => { - if (status === "inProgress") { - return
Generating response: {state.response}
; - } else { - return
Done generating response
; - } - }, -}); -``` - - JSON feedback example + CoAgents demonstration -
- - - ### Stream agent state - - - ### Frontend - - All you need to do to get the current LangGraph agent state is call `useCoAgent`. - - ```tsx - const { state } = useCoAgent({ - name: "search_agent", // the name of the agent - }); - ``` - - ### LangGraph - The LangGraph state only updates when leaving a LangGraph node. - If you want to stream state updates to the frontend as they are generated, you can do so by one of the following methods: - - #### Intercept tool calls - - If you would like to stream **intermediate** state to the frontend, you can do so by treating (streaming) tool call arguments as intermediate state: - - ```python - # in python code: - config = copilotkit_customize_config( - config, - emit_intermediate_state=[ - { - "state_key": "steps", # key on the LangGraph state to be updated - "tool": "search", # tool call - "tool_argument": "steps" # argument of the tool call interpreted as intermediate state - }, - ] - ) - - # ... - - response = await ChatOpenAI(model="gpt-4").bind_tools([search_tool], parallel_tool_calls=False, tool_choice="search").ainvoke([ - *state["messages"], - SystemMessage( - content=system_message - ) - ], config) - ``` - - #### Manually Emit State - - You can imperatively emit state by calling `copilotkit_emit_state`: - - ```python - # imperative function: - copilotkit_emit_state(config, {"key": value} ) - ``` - - #### Manually Emit Messages - - To manually emit messages to the frontend, call `copilotkit_emit_message`: - - ```python - # imperative function: - copilotkit_emit_message(config, "Hello, world!") - ``` - - - - - - - - - - - -### Share Agent State - -Sharing agent state allows for collaboration and persistence across different sessions or users. Here's how you can implement this feature: - -```typescript -const { state, setState, start, stop, run } = useCoAgent({ - name: "search_agent", -}); - -// ... -setState(newStateEditedByUser); -run(() => new TextMessage({ role: MessageRole.System, content: "the user has updated the state" })); // optionally provide a hint about why the agent state changed. -``` - -Just like before, we use the `state` variable on `useCoAgent` to receive the latest agent state. -Now we additionally intercept 4 more of `useCoAgent`'s returned values: - -- `setState`: A function to update the agent's state manually -- `start`: A function to initiate the agent's execution -- `stop`: A function to halt the agent's execution -- `run`: A function to re-run the agent, after updating the state. Optionally include a hint for why the state changed. - - - - - ### Agent Q&A - -Agents can easily and intentionally ask the user questions. With support for: - -- **Text Feedback:** Via the chat UI. -- **Structured (JSON) Feedback:** Via fully custom UI/UX anywhere in your application (chat UI, modals, popups, forms, etc). - -
- -
-
-
-
- -
- Text Feedback -
-
- -
-
-
-
-
- -
- Structured (JSON) Feedback -
-
- -
-
-
- -We will soon add native & seamless Agent Q&A support in `useCoagentStateRender`. - -In the meantime, you can achieve agent Q&A in the following way: - -1. Use `useCoagentStateRender` to render your "Question" LangGraph node (via the exposed state). -2. In your LangGraph, go to an `END` node, or use a breakpoint, to wait for user input. -3. In the `useCoagentStateRender` render function, call `setState` provided by `useCoAgent` to provide the "answer" in the graph state. -4. After the answer is provided via the agent state, navigate to your relevant 'answer' node. For convenience, [you can use the `then` argument on LangGraph's `add_conditional_edges`](https://langchain-ai.github.io/langgraph/reference/graphs/#stategraph) - -
- - -