Add LangGraph integration guide (#271)
This commit is contained in:
parent
2945f6bb3c
commit
2ffa7b7b30
|
|
@ -63,7 +63,11 @@
|
|||
"groups": [
|
||||
{
|
||||
"group": "Getting Started",
|
||||
"pages": ["v2/guides/overview", "v2/guides/mcp"]
|
||||
"pages": ["v2/guides/overview"]
|
||||
},
|
||||
{
|
||||
"group": "Integrations",
|
||||
"pages": ["v2/integrations/langgraph", "v2/integrations/mcp"]
|
||||
},
|
||||
{
|
||||
"group": "Application Interfaces",
|
||||
|
|
|
|||
|
|
@ -14,17 +14,26 @@ Whether you're integrating Honcho into existing platforms, exploring advanced fe
|
|||
Each spellbook focuses on a specific use case with working code you can adapt to your needs. The goal is to get you from idea to working prototype as quickly as possible, then provide the depth you need to scale and customize.
|
||||
|
||||
|
||||
## Getting Started
|
||||
Quick integration guides to get up and running:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="MCP Integration" icon="link" href="/v2/integrations/mcp">
|
||||
Get Honcho running with a single prompt in Claude Code
|
||||
</Card>
|
||||
<Card title="LangGraph" icon="diagram-project" href="/v2/integrations/langgraph">
|
||||
Add persistent memory and theory of mind to your LangGraph agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Application Interfaces
|
||||
Ready-to-use integration patterns for popular platforms:
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Discord Bot" icon="discord" href="/v2/guides/discord">
|
||||
Build a Discord bot that remembers users across conversations
|
||||
</Card>
|
||||
<Card title="Telegram Bot" icon="telegram" href="/v2/guides/telegram">
|
||||
Create a Telegram bot with persistent user understanding
|
||||
</Card>
|
||||
<Card title="MCP" icon="link" href="/v2/guides/mcp">
|
||||
Get Honcho running with a single prompt in Cursor or Claude Code
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,363 @@
|
|||
---
|
||||
title: "LangGraph"
|
||||
icon: 'diagram-project'
|
||||
description: "Build a stateful conversational AI agent with LangGraph and Honcho"
|
||||
sidebarTitle: 'LangGraph'
|
||||
---
|
||||
|
||||
Integrate Honcho with LangGraph to build a conversational AI agent that maintains memory across sessions. This guide shows you how to use Honcho's memory layer with LangGraph's orchestration.
|
||||
|
||||
<Note>
|
||||
The full code is available on [GitHub](https://github.com/plastic-labs/honcho/tree/main/examples/langgraph) with examples in both [Python](https://github.com/plastic-labs/honcho/blob/main/examples/langgraph/python/main.py) and [TypeScript](https://github.com/plastic-labs/honcho/blob/main/examples/langgraph/typescript/main.ts)
|
||||
</Note>
|
||||
|
||||
## What We're Building
|
||||
|
||||
We'll create a conversational agent that remembers and reasons over past exchanges with the user. Here's how the pieces fit together:
|
||||
|
||||
- **LangGraph** orchestrates the conversation flow
|
||||
- **Honcho** stores messages and retrieves relevant context
|
||||
- **Your LLM** generates responses using Honcho's formatted context
|
||||
|
||||
The key benefit: You don't manually manage conversation history, token limits, or message formatting. Honcho handles memory so you can focus on your agent's logic.
|
||||
|
||||
<Note>
|
||||
This tutorial demonstrates a simple linear conversation flow to show
|
||||
how Honcho integrates with LangGraph. For production applications,
|
||||
you'll likely want to add LangGraph features like conditional routing,
|
||||
tool calling, and multi-agent orchestration.
|
||||
</Note>
|
||||
|
||||
## Setup
|
||||
|
||||
Install required packages:
|
||||
|
||||
<CodeGroup>
|
||||
```bash Python (uv)
|
||||
uv add honcho-ai langgraph langchain-core openai python-dotenv
|
||||
```
|
||||
|
||||
```bash Python (pip)
|
||||
pip install honcho-ai langgraph langchain-core openai python-dotenv
|
||||
```
|
||||
|
||||
```bash TypeScript (npm)
|
||||
npm install @honcho-ai/sdk @langchain/langgraph openai dotenv
|
||||
```
|
||||
|
||||
```bash TypeScript (yarn)
|
||||
yarn add @honcho-ai/sdk @langchain/langgraph openai dotenv
|
||||
```
|
||||
|
||||
```bash TypeScript (pnpm)
|
||||
pnpm add @honcho-ai/sdk @langchain/langgraph openai dotenv
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
This tutorial uses OpenAI, but Honcho works with any LLM provider. Create a `.env` file with your API keys:
|
||||
|
||||
```bash
|
||||
OPENAI_API_KEY=your_openai_key
|
||||
```
|
||||
|
||||
<Note>
|
||||
This tutorial uses the Honcho demo server at https://demo.honcho.dev which runs a small instance of Honcho on the latest version. For production, get your Honcho API key at [app.honcho.dev](https://app.honcho.dev). For local development, use `environment="local"`.
|
||||
</Note>
|
||||
|
||||
## Initialize Clients
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from typing_extensions import TypedDict
|
||||
from honcho import Honcho, Peer, Session
|
||||
from openai import OpenAI
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# Initialize Honcho
|
||||
honcho = Honcho()
|
||||
|
||||
# Initialize OpenAI
|
||||
llm = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
|
||||
```
|
||||
|
||||
```typescript TypeScript
|
||||
import * as dotenv from "dotenv";
|
||||
import { Honcho, Peer, Session } from "@honcho-ai/sdk";
|
||||
import OpenAI from "openai";
|
||||
import { Annotation } from "@langchain/langgraph";
|
||||
import { StateGraph, START, END } from "@langchain/langgraph";
|
||||
import * as readline from "readline/promises";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
// Initialize Honcho
|
||||
const honcho = new Honcho({});
|
||||
|
||||
// Initialize OpenAI
|
||||
const llm = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY
|
||||
});
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Define LangGraph State
|
||||
|
||||
Define your state schema to pass data through the graph. The state stores Honcho objects directly along with the current user message and assistant response.
|
||||
|
||||
<Note>
|
||||
Before proceeding, it's important to understand Honcho's core concepts (`Peers` and `Sessions`). Review the [Honcho Architecture](/v2/documentation/core-concepts/architecture) to familiarize yourself with these primitives.
|
||||
</Note>
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
class State(TypedDict):
|
||||
user_message: str
|
||||
assistant_response: str
|
||||
user: Peer
|
||||
assistant: Peer
|
||||
session: Session
|
||||
```
|
||||
|
||||
```typescript TypeScript
|
||||
const StateAnnotation = Annotation.Root({
|
||||
userMessage: Annotation<string>(),
|
||||
assistantResponse: Annotation<string>(),
|
||||
user: Annotation<Peer>(),
|
||||
assistant: Annotation<Peer>(),
|
||||
session: Annotation<Session>(),
|
||||
});
|
||||
|
||||
type State = typeof StateAnnotation.State;
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Build the LangGraph
|
||||
|
||||
Define your chatbot logic, using Honcho to retrieve conversation context. This function demonstrates how Honcho can store messages, retrieve context, and generate responses.
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
def chatbot(state: State):
|
||||
user_message = state["user_message"]
|
||||
|
||||
# Get objects from state
|
||||
user = state["user"]
|
||||
assistant = state["assistant"]
|
||||
session = state["session"]
|
||||
|
||||
# Step 1: Store the user's message in the session
|
||||
# This adds it to Honcho's memory for future context retrieval
|
||||
session.add_messages([user.message(user_message)])
|
||||
|
||||
# Step 2: Get context in OpenAI format with token limit
|
||||
# get_context() retrieves relevant conversation history
|
||||
# tokens=2000 limits the context to 2000 tokens to manage costs and fit within model limits
|
||||
# to_openai() converts it to the format expected by OpenAI's API
|
||||
messages = session.get_context(tokens=2000).to_openai(assistant=assistant)
|
||||
|
||||
# Step 3: Generate response using the context
|
||||
response = llm.chat.completions.create(
|
||||
model="gpt-5.1",
|
||||
messages=messages
|
||||
)
|
||||
assistant_response = response.choices[0].message.content
|
||||
|
||||
# Step 4: Store assistant response in Honcho for future context
|
||||
session.add_messages([assistant.message(assistant_response)])
|
||||
|
||||
return {"assistant_response": assistant_response}
|
||||
```
|
||||
|
||||
```typescript TypeScript
|
||||
async function chatbot(state: State) {
|
||||
const userMessage = state.userMessage;
|
||||
|
||||
// Get objects from state
|
||||
const user = state.user;
|
||||
const assistant = state.assistant;
|
||||
const session = state.session;
|
||||
|
||||
// Step 1: Store the user's message in the session
|
||||
// This adds it to Honcho's memory for future context retrieval
|
||||
await session.addMessages([user.message(userMessage)]);
|
||||
|
||||
// Step 2: Get context in OpenAI format with token limit
|
||||
// getContext() retrieves relevant conversation history
|
||||
// tokens: 2000 limits the context to 2000 tokens to manage costs and fit within model limits
|
||||
// toOpenAI() converts it to the format expected by OpenAI's API
|
||||
const messages = (await session.getContext({ tokens: 2000 })).toOpenAI(assistant);
|
||||
|
||||
// Step 3: Generate response using the context
|
||||
const response = await llm.chat.completions.create({
|
||||
model: "gpt-5.1",
|
||||
messages: messages
|
||||
});
|
||||
const assistantResponse = response.choices[0].message.content!;
|
||||
|
||||
// Step 4: Store assistant response for future context
|
||||
await session.addMessages([assistant.message(assistantResponse)]);
|
||||
|
||||
return { assistantResponse: assistantResponse };
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Now let's build the LangGraph:
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
graph = StateGraph(State) \
|
||||
.add_node("chatbot", chatbot) \
|
||||
.add_edge(START, "chatbot") \
|
||||
.add_edge("chatbot", END) \
|
||||
.compile()
|
||||
```
|
||||
|
||||
```typescript TypeScript
|
||||
const graph = new StateGraph(StateAnnotation)
|
||||
.addNode("chatbot", chatbot)
|
||||
.addEdge(START, "chatbot")
|
||||
.addEdge("chatbot", END)
|
||||
.compile();
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Understanding get_context()
|
||||
|
||||
The [`get_context()`](/v2/documentation/core-concepts/features/get-context) method retrieves comprehensive conversation context and formats it for your LLM. It automatically:
|
||||
|
||||
- **Manages conversation history** - Tracks all messages and determines what's relevant
|
||||
- **Respects token limits** - Stays within context window constraints without manual counting
|
||||
- **Handles long conversations** - Combines recent detailed messages with summaries of older exchanges
|
||||
- **Provides peer understanding** - Includes theory-of-mind representations and peer cards when requested
|
||||
|
||||
The `SessionContext` object always includes fields for messages, summaries, peer representations, and peer cards. By default, only `messages` and `summary` are populated. To populate peer-specific context, pass a `peer_target` parameter:
|
||||
|
||||
**Using `peer_target` for Context:**
|
||||
|
||||
- **Without `peer_perspective`**: Returns Honcho's omniscient view of `peer_target` (all observations and context)
|
||||
- **With `peer_perspective`**: Returns what `peer_perspective` knows about `peer_target` (perspective-based observations and context)
|
||||
|
||||
That's it. Call `session.get_context().to_openai(assistant)` and you get properly formatted context tailored for your assistant.
|
||||
|
||||
<Tip>
|
||||
**Adding System Prompts:** Since `get_context()` returns conversation messages, you can easily prepend custom system instructions. Just add your system prompt to the beginning of the messages array before sending it to your LLM: `[{"role": "system", "content": "..."}, ...context_messages]`.
|
||||
</Tip>
|
||||
|
||||
<Note>
|
||||
For more details on all available parameters, see [`get_context() documentation`](/v2/documentation/core-concepts/features/get-context)
|
||||
</Note>
|
||||
|
||||
## Chat Loop
|
||||
|
||||
Now we'll create the main conversation function. To simplify logic, we initialize Honcho objects once per conversation and pass them through the LangGraph state.
|
||||
|
||||
The `run_conversation_turn` function initializes a Honcho `Session` and `Peer` objects, passes them to the LangGraph, and returns the assistant's response. By calling it repeatedly with the same `user_id` and in the same session, the chat builds context over time.
|
||||
|
||||
<Note>
|
||||
**Production Usage:** Honcho accepts any nanoid-compatible string for `user_id` and `session_id`. You can use IDs directly from your authentication system (Auth0, Firebase, Clerk, etc.) and session management without modification.
|
||||
|
||||
This tutorial uses hardcoded values for simplicity.
|
||||
</Note>
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
def run_conversation_turn(user_id: str, user_input: str, session_id: str | None = None):
|
||||
if not session_id:
|
||||
session_id = f"session_{user_id}"
|
||||
|
||||
# Initialize Honcho objects
|
||||
user = honcho.peer(user_id)
|
||||
assistant = honcho.peer("assistant")
|
||||
session = honcho.session(session_id)
|
||||
|
||||
result = graph.invoke({
|
||||
"user_message": user_input,
|
||||
"user": user,
|
||||
"assistant": assistant,
|
||||
"session": session
|
||||
})
|
||||
|
||||
return result["assistant_response"]
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Welcome to the AI Assistant! How can I help you today?")
|
||||
user_id = "test-user-123"
|
||||
while True:
|
||||
user_input = input("You: ")
|
||||
if user_input.lower() in ['quit', 'exit']:
|
||||
break
|
||||
response = run_conversation_turn(user_id, user_input)
|
||||
print(f"Assistant: {response}\n")
|
||||
```
|
||||
|
||||
```typescript TypeScript
|
||||
async function runConversationTurn(
|
||||
userId: string,
|
||||
userInput: string,
|
||||
sessionId?: string
|
||||
): Promise<string> {
|
||||
if (!sessionId) {
|
||||
sessionId = `session_${userId}`;
|
||||
}
|
||||
|
||||
// Initialize Honcho objects
|
||||
const user = await honcho.peer(userId);
|
||||
const assistant = await honcho.peer("assistant");
|
||||
const session = await honcho.session(sessionId);
|
||||
|
||||
const result = await graph.invoke({
|
||||
userMessage: userInput,
|
||||
user: user,
|
||||
assistant: assistant,
|
||||
session: session,
|
||||
});
|
||||
|
||||
return result.assistantResponse;
|
||||
}
|
||||
|
||||
// Interactive chat loop
|
||||
async function main() {
|
||||
console.log("Welcome to the AI Assistant! How can I help you today?");
|
||||
const userId = "test-user-123";
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
while (true) {
|
||||
const userInput = await rl.question("You: ");
|
||||
if (userInput.toLowerCase() === "quit" || userInput.toLowerCase() === "exit") {
|
||||
rl.close();
|
||||
break;
|
||||
}
|
||||
const response = await runConversationTurn(userId, userInput);
|
||||
console.log(`Assistant: ${response}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Next Steps
|
||||
|
||||
Now that you have a working LangGraph integration with Honcho, you can:
|
||||
|
||||
- **Create custom [LangChain tools](https://docs.langchain.com/oss/python/langchain/tools#customize-tool-properties) for your agent** - to fully utilize Honcho's memory & context management features
|
||||
- **Build a multi-agent LangGraph** where each agent is a Honcho `Peer` with its own memory
|
||||
|
||||
## Related Resources
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Get Context" icon="messages" href="/v2/documentation/core-concepts/features/get-context">
|
||||
Learn more about retrieving and formatting conversation context
|
||||
</Card>
|
||||
<Card title="MCP Integration" icon="star-of-life" href="/v2/integrations/mcp">
|
||||
Use Honcho in Claude Desktop with MCP
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: "Honcho MCP"
|
||||
title: "Model Context Protocol (MCP)"
|
||||
icon: 'star-of-life'
|
||||
description: "Use Honcho in Claude Desktop"
|
||||
sidebarTitle: 'MCP Integration'
|
||||
sidebarTitle: 'MCP'
|
||||
---
|
||||
|
||||
You can let Claude use Honcho to manage its own memory in the native desktop app by using the Honcho MCP integration! Follow these steps:
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
"""
|
||||
LangGraph Integration with Honcho and OpenAI
|
||||
|
||||
This module demonstrates how to build a stateful conversational AI agent using
|
||||
LangGraph for orchestration, OpenAI for the AI model, and Honcho for memory
|
||||
management. It creates a chatbot that remembers conversations across sessions.
|
||||
"""
|
||||
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from typing_extensions import TypedDict
|
||||
from honcho import Honcho, Peer, Session
|
||||
from openai import OpenAI
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
load_dotenv()
|
||||
|
||||
honcho = Honcho()
|
||||
|
||||
llm = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
|
||||
|
||||
class State(TypedDict):
|
||||
user_message: str
|
||||
assistant_response: str
|
||||
user: Peer
|
||||
assistant: Peer
|
||||
session: Session
|
||||
|
||||
def chatbot(state: State):
|
||||
user_message = state["user_message"]
|
||||
|
||||
# Get objects from state
|
||||
user = state["user"]
|
||||
assistant = state["assistant"]
|
||||
session = state["session"]
|
||||
session.add_messages([user.message(user_message)])
|
||||
|
||||
# Get context in OpenAI format with token limit
|
||||
# tokens=2000 limits the context to 2000 tokens to manage costs and fit within model limits
|
||||
messages = session.get_context(tokens=2000).to_openai(assistant=assistant)
|
||||
|
||||
# Generate response
|
||||
response = llm.chat.completions.create(
|
||||
model="gpt-5.1",
|
||||
messages=messages
|
||||
)
|
||||
assistant_response = response.choices[0].message.content
|
||||
|
||||
# Store assistant response
|
||||
session.add_messages([assistant.message(assistant_response)])
|
||||
|
||||
return {"assistant_response": assistant_response}
|
||||
|
||||
graph = StateGraph(State) \
|
||||
.add_node("chatbot", chatbot) \
|
||||
.add_edge(START, "chatbot") \
|
||||
.add_edge("chatbot", END) \
|
||||
.compile()
|
||||
|
||||
def run_conversation_turn(user_id: str, user_input: str, session_id: str | None = None):
|
||||
if not session_id:
|
||||
session_id = f"session_{user_id}"
|
||||
|
||||
# Initialize Honcho objects
|
||||
user = honcho.peer(user_id)
|
||||
assistant = honcho.peer("assistant")
|
||||
session = honcho.session(session_id)
|
||||
|
||||
result = graph.invoke({
|
||||
"user_message": user_input,
|
||||
"user": user,
|
||||
"assistant": assistant,
|
||||
"session": session
|
||||
})
|
||||
|
||||
return result["assistant_response"]
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Welcome to the AI Assistant! How can I help you today?")
|
||||
user_id = "test-user-1234"
|
||||
while True:
|
||||
user_input = input("You: ")
|
||||
if user_input.lower() in ['quit', 'exit']:
|
||||
break
|
||||
response = run_conversation_turn(user_id, user_input)
|
||||
print(f"Assistant: {response}\n")
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
[project]
|
||||
name = "honcho-langgraph-example"
|
||||
version = "0.1.0"
|
||||
description = "LangGraph integration with Honcho for stateful conversational AI"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"honcho-ai",
|
||||
"langchain-core>=1.0.6",
|
||||
"langgraph>=1.0.3",
|
||||
"openai>=1.99.7",
|
||||
"python-dotenv>=1.1.1",
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,179 @@
|
|||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "honcho-langgraph-example",
|
||||
"dependencies": {
|
||||
"@honcho-ai/sdk": "^1.5.0",
|
||||
"@langchain/langgraph": "^1.0.2",
|
||||
"dotenv": "^17.2.3",
|
||||
"openai": "^6.9.1",
|
||||
"zod": "4.0.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.2",
|
||||
"typescript": "^5.7.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@cfworker/json-schema": ["@cfworker/json-schema@4.1.1", "", {}, "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og=="],
|
||||
|
||||
"@honcho-ai/core": ["@honcho-ai/core@1.5.1", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-lbYtMTcL2AxdcIl5ZKenogeTlVMnE7buJWvAFOCLp0yQxcezyA/R9FPvLz2UGRApLsiplLNWhftML+3QBjIIJA=="],
|
||||
|
||||
"@honcho-ai/sdk": ["@honcho-ai/sdk@1.5.0", "", { "dependencies": { "@honcho-ai/core": "^1.5.1", "@types/node": "^24.0.1", "zod": "4.0.0" } }, "sha512-1V3wnIxyoRw0oYDE1p6GG4vRpwnn0PkwYsb4z4NeJkmWaafS9So1G32+IPhm01i2s4RnxsU31kCVL07BRsqtUw=="],
|
||||
|
||||
"@langchain/core": ["@langchain/core@1.0.6", "", { "dependencies": { "@cfworker/json-schema": "^4.0.2", "ansi-styles": "^5.0.0", "camelcase": "6", "decamelize": "1.2.0", "js-tiktoken": "^1.0.12", "langsmith": "^0.3.64", "mustache": "^4.2.0", "p-queue": "^6.6.2", "p-retry": "4", "uuid": "^10.0.0", "zod": "^3.25.76 || ^4" } }, "sha512-rDSjXATujCdJlL+OJFfyZhEca8kLmqGr4W2ebJvSHiUgXEDqu/IOWC+ZWgoKKHkGOGFdVTqQ7Qi0j2RnYS9Qlg=="],
|
||||
|
||||
"@langchain/langgraph": ["@langchain/langgraph@1.0.2", "", { "dependencies": { "@langchain/langgraph-checkpoint": "^1.0.0", "@langchain/langgraph-sdk": "~1.0.0", "uuid": "^10.0.0" }, "peerDependencies": { "@langchain/core": "^1.0.1", "zod": "^3.25.32 || ^4.1.0", "zod-to-json-schema": "^3.x" }, "optionalPeers": ["zod-to-json-schema"] }, "sha512-syxzzWTnmpCL+RhUEvalUeOXFoZy/KkzHa2Da2gKf18zsf9Dkbh3rfnRDrTyUGS1XSTejq07s4rg1qntdEDs2A=="],
|
||||
|
||||
"@langchain/langgraph-checkpoint": ["@langchain/langgraph-checkpoint@1.0.0", "", { "dependencies": { "uuid": "^10.0.0" }, "peerDependencies": { "@langchain/core": "^1.0.1" } }, "sha512-xrclBGvNCXDmi0Nz28t3vjpxSH6UYx6w5XAXSiiB1WEdc2xD2iY/a913I3x3a31XpInUW/GGfXXfePfaghV54A=="],
|
||||
|
||||
"@langchain/langgraph-sdk": ["@langchain/langgraph-sdk@1.0.0", "", { "dependencies": { "p-queue": "^6.6.2", "p-retry": "4", "uuid": "^9.0.0" }, "peerDependencies": { "@langchain/core": "^1.0.1", "react": "^18 || ^19", "react-dom": "^18 || ^19" }, "optionalPeers": ["@langchain/core", "react", "react-dom"] }, "sha512-g25ti2W7Dl5wUPlNK+0uIGbeNFqf98imhHlbdVVKTTkDYLhi/pI1KTgsSSkzkeLuBIfvt2b0q6anQwCs7XBlbw=="],
|
||||
|
||||
"@types/node": ["@types/node@22.19.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ=="],
|
||||
|
||||
"@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="],
|
||||
|
||||
"@types/retry": ["@types/retry@0.12.0", "", {}, "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="],
|
||||
|
||||
"@types/uuid": ["@types/uuid@10.0.0", "", {}, "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ=="],
|
||||
|
||||
"abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],
|
||||
|
||||
"agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
|
||||
|
||||
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
||||
|
||||
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||
|
||||
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
||||
|
||||
"camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="],
|
||||
|
||||
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||
|
||||
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||
|
||||
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||
|
||||
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
|
||||
|
||||
"console-table-printer": ["console-table-printer@2.15.0", "", { "dependencies": { "simple-wcswidth": "^1.1.2" } }, "sha512-SrhBq4hYVjLCkBVOWaTzceJalvn5K1Zq5aQA6wXC/cYjI3frKWNPEMK3sZsJfNNQApvCQmgBcc13ZKmFj8qExw=="],
|
||||
|
||||
"decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="],
|
||||
|
||||
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
|
||||
|
||||
"dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="],
|
||||
|
||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||
|
||||
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
||||
|
||||
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
||||
|
||||
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
|
||||
|
||||
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
|
||||
|
||||
"event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="],
|
||||
|
||||
"eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="],
|
||||
|
||||
"form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="],
|
||||
|
||||
"form-data-encoder": ["form-data-encoder@1.7.2", "", {}, "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="],
|
||||
|
||||
"formdata-node": ["formdata-node@4.4.1", "", { "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" } }, "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ=="],
|
||||
|
||||
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||
|
||||
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
|
||||
|
||||
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
||||
|
||||
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
||||
|
||||
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
||||
|
||||
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
||||
|
||||
"has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
|
||||
|
||||
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||
|
||||
"humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="],
|
||||
|
||||
"js-tiktoken": ["js-tiktoken@1.0.21", "", { "dependencies": { "base64-js": "^1.5.1" } }, "sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g=="],
|
||||
|
||||
"langsmith": ["langsmith@0.3.80", "", { "dependencies": { "@types/uuid": "^10.0.0", "chalk": "^4.1.2", "console-table-printer": "^2.12.1", "p-queue": "^6.6.2", "p-retry": "4", "semver": "^7.6.3", "uuid": "^10.0.0" }, "peerDependencies": { "@opentelemetry/api": "*", "@opentelemetry/exporter-trace-otlp-proto": "*", "@opentelemetry/sdk-trace-base": "*", "openai": "*" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/exporter-trace-otlp-proto", "@opentelemetry/sdk-trace-base", "openai"] }, "sha512-BWpbB9/Hkx06S5X4nJE3W5Wm1mH/j6SIqWcM/WAuT+yulohE9knstIJGmBpmSBULb46nCj+cfjRkyF1Nrc4UmA=="],
|
||||
|
||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||
|
||||
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
|
||||
|
||||
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="],
|
||||
|
||||
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
|
||||
|
||||
"node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
|
||||
|
||||
"openai": ["openai@6.9.1", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-vQ5Rlt0ZgB3/BNmTa7bIijYFhz3YBceAA3Z4JuoMSBftBF9YqFHIEhZakSs+O/Ad7EaoEimZvHxD5ylRjN11Lg=="],
|
||||
|
||||
"p-finally": ["p-finally@1.0.0", "", {}, "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow=="],
|
||||
|
||||
"p-queue": ["p-queue@6.6.2", "", { "dependencies": { "eventemitter3": "^4.0.4", "p-timeout": "^3.2.0" } }, "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ=="],
|
||||
|
||||
"p-retry": ["p-retry@4.6.2", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="],
|
||||
|
||||
"p-timeout": ["p-timeout@3.2.0", "", { "dependencies": { "p-finally": "^1.0.0" } }, "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg=="],
|
||||
|
||||
"retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="],
|
||||
|
||||
"semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
|
||||
|
||||
"simple-wcswidth": ["simple-wcswidth@1.1.2", "", {}, "sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw=="],
|
||||
|
||||
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||
|
||||
"tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
|
||||
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
|
||||
"uuid": ["uuid@10.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="],
|
||||
|
||||
"web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="],
|
||||
|
||||
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
|
||||
|
||||
"whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
|
||||
|
||||
"zod": ["zod@4.0.0", "", {}, "sha512-9diLdTPc/L7w/5jI4C3gHYNiGHDV9IZYxo1e5LSD8cabi65WVTWWb+g2BGPEpUUCOxR4D+6O5B0AzyMdUAXwrw=="],
|
||||
|
||||
"@honcho-ai/core/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="],
|
||||
|
||||
"@honcho-ai/sdk/@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="],
|
||||
|
||||
"@langchain/langgraph-sdk/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
|
||||
|
||||
"@types/node-fetch/@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="],
|
||||
|
||||
"chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
"@honcho-ai/core/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
|
||||
|
||||
"@honcho-ai/sdk/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||
|
||||
"@types/node-fetch/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/**
|
||||
* LangGraph Integration with Honcho and OpenAI
|
||||
*
|
||||
* This module demonstrates how to build a stateful conversational AI agent using
|
||||
* LangGraph for orchestration, OpenAI for the AI model, and Honcho for memory
|
||||
* management. It creates a chatbot that remembers conversations across sessions.
|
||||
*/
|
||||
|
||||
import * as dotenv from "dotenv";
|
||||
import { Honcho, Peer, Session } from "@honcho-ai/sdk";
|
||||
import OpenAI from "openai";
|
||||
import { Annotation } from "@langchain/langgraph";
|
||||
import { StateGraph, START, END } from "@langchain/langgraph";
|
||||
import * as readline from "readline/promises";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const honcho = new Honcho({});
|
||||
|
||||
const llm = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY
|
||||
});
|
||||
|
||||
const StateAnnotation = Annotation.Root({
|
||||
userMessage: Annotation<string>(),
|
||||
assistantResponse: Annotation<string>(),
|
||||
user: Annotation<Peer>(),
|
||||
assistant: Annotation<Peer>(),
|
||||
session: Annotation<Session>(),
|
||||
});
|
||||
|
||||
type State = typeof StateAnnotation.State;
|
||||
|
||||
async function chatbot(state: State) {
|
||||
const userMessage = state.userMessage;
|
||||
|
||||
// Get objects from state
|
||||
const user = state.user;
|
||||
const assistant = state.assistant;
|
||||
const session = state.session;
|
||||
await session.addMessages([user.message(userMessage)]);
|
||||
|
||||
// Get context in OpenAI format with token limit
|
||||
// tokens: 2000 limits the context to 2000 tokens to manage costs and fit within model limits
|
||||
const messages = (await session.getContext({ tokens: 2000 })).toOpenAI(assistant);
|
||||
|
||||
// Generate response
|
||||
const response = await llm.chat.completions.create({
|
||||
model: "gpt-4o",
|
||||
messages: messages
|
||||
});
|
||||
const assistantResponse = response.choices[0].message.content!;
|
||||
|
||||
// Store assistant response
|
||||
await session.addMessages([assistant.message(assistantResponse)]);
|
||||
|
||||
return { assistantResponse: assistantResponse };
|
||||
}
|
||||
|
||||
const graph = new StateGraph(StateAnnotation)
|
||||
.addNode("chatbot", chatbot)
|
||||
.addEdge(START, "chatbot")
|
||||
.addEdge("chatbot", END)
|
||||
.compile();
|
||||
|
||||
async function runConversationTurn(
|
||||
userId: string,
|
||||
userInput: string,
|
||||
sessionId?: string
|
||||
): Promise<string> {
|
||||
if (!sessionId) {
|
||||
sessionId = `session_${userId}`;
|
||||
}
|
||||
|
||||
// Initialize Honcho objects
|
||||
const user = await honcho.peer(userId);
|
||||
const assistant = await honcho.peer("assistant");
|
||||
const session = await honcho.session(sessionId);
|
||||
|
||||
const result = await graph.invoke({
|
||||
userMessage: userInput,
|
||||
user: user,
|
||||
assistant: assistant,
|
||||
session: session,
|
||||
});
|
||||
|
||||
return result.assistantResponse;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log("Welcome to the AI Assistant! How can I help you today?");
|
||||
const userId = "test-user-1234";
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
while (true) {
|
||||
const userInput = await rl.question("You: ");
|
||||
if (userInput.toLowerCase() === "quit" || userInput.toLowerCase() === "exit") {
|
||||
rl.close();
|
||||
break;
|
||||
}
|
||||
const response = await runConversationTurn(userId, userInput);
|
||||
console.log(`Assistant: ${response}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "honcho-langgraph-example",
|
||||
"version": "1.0.0",
|
||||
"description": "LangGraph integration with Honcho for stateful conversational AI",
|
||||
"main": "main.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "bun run main.ts",
|
||||
"dev": "bun --watch main.ts"
|
||||
},
|
||||
"keywords": [
|
||||
"honcho",
|
||||
"langgraph",
|
||||
"openai",
|
||||
"chatbot",
|
||||
"ai"
|
||||
],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@honcho-ai/sdk": "^1.5.0",
|
||||
"@langchain/langgraph": "^1.0.2",
|
||||
"dotenv": "^17.2.3",
|
||||
"openai": "^6.9.1",
|
||||
"zod": "4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.2",
|
||||
"typescript": "^5.7.2"
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue