docs/content/docs/integrations/langgraph/tutorials/agent-native-app/step-6-shared-state.mdx
import { ImageZoom } from 'fumadocs-ui/components/image-zoom';
In LangGraph, your agents are stateful. This means that they as your graph traverses nodes, the overall application state will be updated and persisted.
CopilotKit allows you to easily read and update this state through the use of two main hooks:
useCoAgent - Provides a way to read and write Agent state anywhere in your application.useCoAgentStateRender - Provides a way to render Agent state in the chat.With this in mind, our current goal is to create a bidirectional connection between the application's state and the LangChain agent's state. This will allow us to render the agent's completed research in the right panel.
For this, we'll be using the useCoAgent hook.
# ...
from typing import Dict, Union, List
from langgraph.graph import MessagesState
class ResearchState(MessagesState):
title: str
proposal: Dict[str, Union[str, bool, Dict[str, Union[str, bool]]]] # Stores proposed structure before user approval
outline: dict
sections: List[dict] # list of dicts with 'title','content',and 'idx'
footnotes: str
sources: Dict[str, Dict[str, Union[str, float]]]
tool: str
logs: List[dict] # list of dicts logs to be sent to frontend with 'message', 'status'
There are a few things to note here, but let's focus on the proposal field and sections field.
proposal field is a dictionary that stores the proposed research structure before the user approves it.sections field is a list of dictionaries, each containing a title, content, and idx. This is the actual research that will be displayed in the right panel.We've already wired up the approval of the proposal field in the previous step, so now we need to wire up rendering for the sections field.
useCoAgent hookOur current goal is to create a bidirectional connection between these two states. Luckily, the useCoAgent hook makes this easy.
In the useResearch hook, we'll just replace our React state objects with the useCoAgent hook.
// ...
import { useAgent } from "@copilotkit/react-core/v2"; // [!code ++]
// ...
interface ResearchContextType {
state: ResearchState;
setResearchState: (newState: ResearchState | ((prevState: ResearchState) => ResearchState)) => void
sourcesModalOpen: boolean
setSourcesModalOpen: (open: boolean) => void
runAgent: () => void
}
const ResearchContext = createContext<ResearchContextType | undefined>(undefined)
export function ResearchProvider({ children }: { children: ReactNode }) {
const [sourcesModalOpen, setSourcesModalOpen] = useState<boolean>(false)
// [!code ++:5]
const { state, setState, run } = useAgent<ResearchState>({
name: 'agent',
initialState: {},
});
const [state, setState] = useState<ResearchState>({} as ResearchState) // [!code --]
// ...
return (
<ResearchContext.Provider
value={{
state,
setResearchState: setState as ResearchContextType['setResearchState'],
setSourcesModalOpen,
sourcesModalOpen,
runAgent: run // [!code ++]
runAgent: () => {} // [!code --]
}}>
{children}
</ResearchContext.Provider>
)
}
export function useResearch() {
const context = useContext(ResearchContext)
if (context === undefined) {
throw new Error('useResearch must be used within a ResearchProvider')
}
return context
}
It is not recommended, but you can ditch the type parameter and instead get an any type.
</Callout>
In this example, we use the useCoAgent hook to wire up the application's state to the LangChain agent's state.
AgentState type that was already defined for the application in @/lib/types.ts.name parameter, we pass the name of the graph as defined in agent/langgraph.json.initialState parameter, we pass the initial state of the LangChain agent which is already defined in @/lib/trips.ts.
</Step>
Now we can see the final result of the research in the right panel! To recap, we did the following:
useCoAgent hook to our application to render the sections field.Now, try running the agent again and going through the same steps. At the end, you'll see the completed research in the right panel.
Please research dogs!
Now, we can completely run our agent from start to finish and see the finalized research in the right window.
However, you may notice that the research takes a long time to complete without any indication of progress. In the next step, we'll leverage the CoAgent concepts of generative ui to communicate the agent's progress in the chat.