-
Notifications
You must be signed in to change notification settings - Fork 912
Expand file tree
/
Copy pathlanggraph-multi-agent.ts
More file actions
118 lines (102 loc) · 3.53 KB
/
Copy pathlanggraph-multi-agent.ts
File metadata and controls
118 lines (102 loc) · 3.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/**
* LangGraph Multi-Agent Example (CascadeFlow + closed tool loops)
*
* Demonstrates (conceptually):
* - A small multi-agent graph where sub-agents can call tools
* - CascadeFlow high-risk tool policy (high-risk tool calls force verifier)
* - Tool-safe streaming behavior when tools are bound
*
* Notes:
* - This example depends on optional LangGraph packages. If you don't use LangGraph,
* skip this file. It is not required for @cascadeflow/langchain itself.
*
* Setup:
* export OPENAI_API_KEY="sk-..."
* pnpm -C packages/langchain-cascadeflow install
* npm i @langchain/langgraph
* npx tsx packages/langchain-cascadeflow/examples/langgraph-multi-agent.ts
*/
import { ChatOpenAI } from '@langchain/openai';
import { withCascade } from '../src/index.js';
// Import lazily so the package remains optional.
async function importLangGraph() {
// eslint-disable-next-line @typescript-eslint/no-var-requires
return await import('@langchain/langgraph');
}
async function main() {
if (!process.env.OPENAI_API_KEY) {
console.log("Set OPENAI_API_KEY first: export OPENAI_API_KEY='sk-...'");
process.exit(1);
}
const { StateGraph, END, Annotation } = await importLangGraph();
const drafter = new ChatOpenAI({ model: 'gpt-4o-mini', temperature: 0.2 });
const verifier = new ChatOpenAI({ model: 'gpt-4o', temperature: 0.2 });
// Shared cascade model; each agent can reuse it.
const baseCascade = withCascade({
drafter,
verifier,
qualityThreshold: 0.7,
costTrackingProvider: 'langsmith',
});
// Example tools.
// Keep descriptions accurate: tool risk classification uses name + description.
const tools = [
{
type: 'function',
function: {
name: 'get_weather',
description: 'Read-only: get the current weather for a location.',
parameters: {
type: 'object',
properties: { location: { type: 'string' } },
required: ['location'],
},
},
},
{
type: 'function',
function: {
name: 'delete_user',
description: 'HIGH RISK: permanently deletes a user account (irreversible).',
parameters: {
type: 'object',
properties: { user_id: { type: 'string' } },
required: ['user_id'],
},
},
},
];
// Binding tools enables tool-safe streaming + high-risk gating.
const cascade = (baseCascade as any).bindTools(tools);
const GraphStateAnnotation = Annotation.Root({
input: Annotation<string>({
reducer: (_x: string, y: string) => y,
default: () => '',
}),
result: Annotation<string | undefined>({
reducer: (_x: string | undefined, y: string | undefined) => y,
default: () => undefined,
}),
});
type GraphState = typeof GraphStateAnnotation.State;
const planner = async (state: GraphState) => {
const msg = await cascade.invoke(state.input, {
tags: ['example', 'langgraph', 'planner'],
metadata: { example: 'langgraph-multi-agent', agent: 'planner' },
});
return { ...state, result: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content) };
};
const graph = new StateGraph(GraphStateAnnotation)
.addNode('planner', planner)
.addEdge('planner', END)
.setEntryPoint('planner');
const app = graph.compile();
const out = await app.invoke({
input: 'Plan steps to fetch weather for Berlin. If any destructive action is needed, propose it but do not execute.',
});
console.log(out.result);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});