Skip to content

Commit 03c18d7

Browse files
authored
graph: support multiturn chat for graph (#423)
1 parent ab21c33 commit 03c18d7

File tree

9 files changed

+542
-14
lines changed

9 files changed

+542
-14
lines changed

agent/graphagent/graph_agent.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
"trpc.group/trpc-go/trpc-agent-go/agent"
1818
"trpc.group/trpc-go/trpc-agent-go/event"
1919
"trpc.group/trpc-go/trpc-agent-go/graph"
20+
"trpc.group/trpc-go/trpc-agent-go/internal/flow/processor"
21+
"trpc.group/trpc-go/trpc-agent-go/model"
2022
"trpc.group/trpc-go/trpc-agent-go/tool"
2123
)
2224

@@ -137,7 +139,7 @@ func (ga *GraphAgent) Run(ctx context.Context, invocation *agent.Invocation) (<-
137139
ga.setupInvocation(invocation)
138140

139141
// Prepare initial state.
140-
initialState := ga.createInitialState(invocation)
142+
initialState := ga.createInitialState(ctx, invocation)
141143

142144
// Execute the graph.
143145
if ga.agentCallbacks != nil {
@@ -165,7 +167,7 @@ func (ga *GraphAgent) Run(ctx context.Context, invocation *agent.Invocation) (<-
165167
return eventChan, nil
166168
}
167169

168-
func (ga *GraphAgent) createInitialState(invocation *agent.Invocation) graph.State {
170+
func (ga *GraphAgent) createInitialState(ctx context.Context, invocation *agent.Invocation) graph.State {
169171
var initialState graph.State
170172

171173
if ga.initialState != nil {
@@ -182,6 +184,23 @@ func (ga *GraphAgent) createInitialState(invocation *agent.Invocation) graph.Sta
182184
}
183185
}
184186

187+
// Seed messages from session events so multi‑turn runs share history.
188+
// This mirrors ContentRequestProcessor behavior used by non-graph flows.
189+
if invocation.Session != nil {
190+
// Build a temporary request to reuse the processor logic.
191+
req := &model.Request{}
192+
// Default processor: IncludeContentsFiltered + AddContextPrefix.
193+
p := processor.NewContentRequestProcessor(
194+
processor.WithIncludeContents(processor.IncludeContentsAll),
195+
processor.WithPreserveSameBranch(true),
196+
)
197+
// We only need messages side effect; no output channel needed.
198+
p.ProcessRequest(ctx, invocation, req, nil)
199+
if len(req.Messages) > 0 {
200+
initialState[graph.StateKeyMessages] = req.Messages
201+
}
202+
}
203+
185204
// Add invocation message to state.
186205
// When resuming from checkpoint, only add user input if it's meaningful content
187206
// (not just a resume signal), following LangGraph's pattern.

examples/graph/multiturn/README.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Graph Multi‑Turn Chat (GraphAgent + Runner)
2+
3+
This example demonstrates an interactive, multi‑turn chat built on the graph package using GraphAgent and Runner. It highlights:
4+
5+
- Persisted conversation history via the session service across turns
6+
- Tool‑augmented LLM chat with a calculator tool and automatic tool routing
7+
- Streaming outputs and interactive REPL experience
8+
- Message‑oriented state with `graph.MessagesStateSchema`
9+
10+
## What It Shows
11+
12+
- Graph‑first design: a single LLM node (`chat`) and a tools node (`tools`), connected with `AddToolsConditionalEdges` so the LLM can call tools when needed, then continue the conversation.
13+
- Natural multi‑turn: every user input is appended to the session; the next run reads full history from the same session so the LLM responds contextually.
14+
- Streaming UX: tokens stream as they arrive, just like other examples.
15+
16+
## Graph Overview
17+
18+
```
19+
Entry: chat (LLM) ──→ tools (when tool calls are present) ──→ back to chat
20+
Finish: chat
21+
```
22+
23+
- Schema: `graph.MessagesStateSchema()`
24+
- Tool:
25+
- `calculator(expression)` → evaluates arithmetic expressions (+, -, *, /, ^, parentheses)
26+
27+
## Usage
28+
29+
### Run
30+
31+
```bash
32+
cd examples/graph/multiturn
33+
go run . -model deepseek-chat
34+
```
35+
36+
Then chat interactively:
37+
38+
```
39+
You: hello
40+
Assistant: …streaming…
41+
42+
You: what is (12.5+3)*2?
43+
Assistant: …calls calculator tool and answers…
44+
```
45+
46+
Type `exit` or `quit` to leave.
47+
48+
Notes:
49+
- The example generates a session ID once per process start and reuses it for all turns in the session, so the assistant has memory across turns.
50+
- To persist the same session across process restarts, you can pin `sessionID` to a fixed value in `main.go`.
51+
52+
## Requirements
53+
54+
- Go 1.21+
55+
- Network access and a compatible LLM model (default: `deepseek-chat`). Set any required API keys (e.g., `OPENAI_API_KEY`).
56+
57+
## Key Files
58+
59+
- `main.go` — builds the graph, wraps it with `GraphAgent`, and runs via `Runner` in an interactive loop.
60+
61+
## Related Examples
62+
63+
- `examples/graph/basic` — richer workflow with conditional routing and formatting
64+
- `examples/runwithmessages` — demonstrates Runner + session seeding from a non‑graph flow

0 commit comments

Comments
 (0)