or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

actions.mdcheckpoints.mdconfiguration.mdgraph-construction.mdgraph-execution.mdindex.mdprebuilt.mdstate-management.md

prebuilt.mddocs/

0

# Prebuilt Components

1

2

Ready-to-use components for common patterns including message handling, specialized state management, and workflow templates.

3

4

## Capabilities

5

6

### MessagesState

7

8

Specialized agent state for handling message-based workflows, commonly used for chat applications and conversational AI systems.

9

10

```java { .api }

11

/**

12

* Agent state specialized for message collections

13

* @param <T> Type of messages stored in the state

14

*/

15

class MessagesState<T> extends AgentState {

16

/**

17

* Default schema with appender channel for messages

18

*/

19

static final Map<String, Channel<?>> SCHEMA;

20

21

/**

22

* Creates MessagesState with initial data

23

* @param initData Initial state data including messages

24

*/

25

MessagesState(Map<String, Object> initData);

26

27

/**

28

* Retrieves the list of messages

29

* @return List of messages in the state

30

* @throws RuntimeException if messages key not found

31

*/

32

List<T> messages();

33

34

/**

35

* Gets the most recent message

36

* @return Optional containing last message if present

37

*/

38

Optional<T> lastMessage();

39

40

/**

41

* Gets message at position N from the end

42

* @param n Position from end (0 = last, 1 = second to last, etc.)

43

* @return Optional containing message at position if exists

44

*/

45

Optional<T> lastMinus(int n);

46

}

47

```

48

49

**Usage Examples:**

50

51

```java

52

// String-based messages

53

class StringMessagesState extends MessagesState<String> {

54

public StringMessagesState(Map<String, Object> initData) {

55

super(initData);

56

}

57

}

58

59

// Create initial state with messages

60

List<String> initialMessages = List.of("Hello", "How can I help?");

61

Map<String, Object> initData = Map.of("messages", new ArrayList<>(initialMessages));

62

StringMessagesState state = new StringMessagesState(initData);

63

64

// Access messages

65

List<String> allMessages = state.messages();

66

Optional<String> lastMsg = state.lastMessage();

67

Optional<String> secondToLast = state.lastMinus(1);

68

69

System.out.println("All messages: " + allMessages);

70

System.out.println("Last message: " + lastMsg.orElse("None"));

71

System.out.println("Previous message: " + secondToLast.orElse("None"));

72

73

// Custom message type

74

class ChatMessage {

75

private final String content;

76

private final String sender;

77

private final long timestamp;

78

79

public ChatMessage(String content, String sender) {

80

this.content = content;

81

this.sender = sender;

82

this.timestamp = System.currentTimeMillis();

83

}

84

85

// getters...

86

public String getContent() { return content; }

87

public String getSender() { return sender; }

88

public long getTimestamp() { return timestamp; }

89

}

90

91

class ChatMessagesState extends MessagesState<ChatMessage> {

92

public ChatMessagesState(Map<String, Object> initData) {

93

super(initData);

94

}

95

}

96

97

// Use with custom message type

98

List<ChatMessage> chatMessages = List.of(

99

new ChatMessage("Hello there!", "user"),

100

new ChatMessage("Hi! How can I assist you?", "assistant")

101

);

102

103

ChatMessagesState chatState = new ChatMessagesState(

104

Map.of("messages", new ArrayList<>(chatMessages))

105

);

106

107

Optional<ChatMessage> lastChatMsg = chatState.lastMessage();

108

if (lastChatMsg.isPresent()) {

109

System.out.println("Last from: " + lastChatMsg.get().getSender());

110

System.out.println("Content: " + lastChatMsg.get().getContent());

111

}

112

```

113

114

### MessagesStateGraph

115

116

Specialized StateGraph for MessagesState that automatically configures message appending behavior.

117

118

```java { .api }

119

/**

120

* StateGraph specialized for MessagesState

121

* @param <T> Type of messages in the state

122

*/

123

class MessagesStateGraph<T> extends StateGraph<MessagesState<T>> {

124

/**

125

* Creates MessagesStateGraph with default constructor factory

126

*/

127

MessagesStateGraph();

128

129

/**

130

* Creates MessagesStateGraph with custom state serializer

131

* @param stateSerializer Serializer for MessagesState instances

132

*/

133

MessagesStateGraph(StateSerializer<MessagesState<T>> stateSerializer);

134

}

135

```

136

137

**Usage Examples:**

138

139

```java

140

// Simple messages graph with default serialization

141

MessagesStateGraph<String> simpleMessagesGraph = new MessagesStateGraph<>();

142

143

// Add nodes that work with messages

144

simpleMessagesGraph.addNode("receive_input", (state) -> {

145

String userInput = state.<String>value("user_input").orElse("");

146

// Messages are automatically appended due to MessagesState.SCHEMA

147

return CompletableFuture.completedFuture(Map.of("messages", List.of(userInput)));

148

});

149

150

simpleMessagesGraph.addNode("generate_response", (state) -> {

151

List<String> messages = state.messages();

152

String lastMessage = state.lastMessage().orElse("");

153

154

// Simple echo response

155

String response = "Echo: " + lastMessage;

156

return CompletableFuture.completedFuture(Map.of("messages", List.of(response)));

157

});

158

159

simpleMessagesGraph.addNode("display_conversation", (state) -> {

160

List<String> messages = state.messages();

161

System.out.println("Conversation history:");

162

for (int i = 0; i < messages.size(); i++) {

163

System.out.println((i + 1) + ". " + messages.get(i));

164

}

165

return CompletableFuture.completedFuture(Map.of("displayed", true));

166

});

167

168

// Set up flow

169

simpleMessagesGraph.addEdge(StateGraph.START, "receive_input");

170

simpleMessagesGraph.addEdge("receive_input", "generate_response");

171

simpleMessagesGraph.addEdge("generate_response", "display_conversation");

172

simpleMessagesGraph.addEdge("display_conversation", StateGraph.END);

173

174

// Compile and run

175

CompiledGraph<MessagesState<String>> app = simpleMessagesGraph.compile();

176

Optional<MessagesState<String>> result = app.invoke(Map.of("user_input", "Hello AI!"));

177

178

if (result.isPresent()) {

179

List<String> finalMessages = result.get().messages();

180

System.out.println("Final conversation: " + finalMessages);

181

}

182

183

// Advanced messages graph with custom serialization

184

StateSerializer<MessagesState<ChatMessage>> chatSerializer =

185

new JacksonStateSerializer<>(ChatMessagesState::new);

186

187

MessagesStateGraph<ChatMessage> chatGraph = new MessagesStateGraph<>(chatSerializer);

188

189

// Add sophisticated chat nodes

190

chatGraph.addNode("process_user_message", (state) -> {

191

String userInput = state.<String>value("user_input").orElse("");

192

ChatMessage userMsg = new ChatMessage(userInput, "user");

193

194

return CompletableFuture.completedFuture(Map.of(

195

"messages", List.of(userMsg),

196

"last_user_input", userInput

197

));

198

});

199

200

chatGraph.addNode("generate_ai_response", (state) -> {

201

String lastUserInput = state.<String>value("last_user_input").orElse("");

202

203

// Simulate AI processing based on conversation history

204

List<ChatMessage> history = state.messages();

205

String context = "Previous messages: " + history.size();

206

String response = generateAIResponse(lastUserInput, context);

207

208

ChatMessage aiMsg = new ChatMessage(response, "assistant");

209

210

return CompletableFuture.completedFuture(Map.of(

211

"messages", List.of(aiMsg),

212

"response_generated", true

213

));

214

});

215

216

// Chat routing based on message analysis

217

chatGraph.addNode("analyze_intent", (state, config) -> {

218

Optional<ChatMessage> lastMsg = state.lastMessage();

219

220

return CompletableFuture.supplyAsync(() -> {

221

if (lastMsg.isPresent() && "user".equals(lastMsg.get().getSender())) {

222

String content = lastMsg.get().getContent().toLowerCase();

223

224

String intent;

225

if (content.contains("goodbye") || content.contains("bye")) {

226

intent = "farewell";

227

} else if (content.contains("help") || content.contains("?")) {

228

intent = "help_request";

229

} else {

230

intent = "general_chat";

231

}

232

233

return new Command(intent, Map.of("detected_intent", intent));

234

}

235

236

return new Command("general_chat", Map.of());

237

});

238

}, Map.of(

239

"farewell", "farewell_handler",

240

"help_request", "help_handler",

241

"general_chat", "general_chat_handler"

242

));

243

244

private String generateAIResponse(String input, String context) {

245

// Simulate AI response generation

246

return "AI response to: " + input + " (Context: " + context + ")";

247

}

248

```

249

250

### Message Processing Patterns

251

252

Common patterns for working with message-based workflows.

253

254

```java { .api }

255

// Message filtering and transformation

256

AsyncNodeAction<MessagesState<ChatMessage>> messageFilter = (state) -> {

257

List<ChatMessage> messages = state.messages();

258

259

// Filter out system messages older than 1 hour

260

long oneHourAgo = System.currentTimeMillis() - 3600000;

261

List<ChatMessage> filtered = messages.stream()

262

.filter(msg -> !"system".equals(msg.getSender()) || msg.getTimestamp() > oneHourAgo)

263

.collect(Collectors.toList());

264

265

return CompletableFuture.completedFuture(Map.of(

266

"messages", filtered,

267

"filtered_count", messages.size() - filtered.size()

268

));

269

};

270

271

// Message summarization

272

AsyncNodeAction<MessagesState<String>> messageSummarizer = (state) -> {

273

List<String> messages = state.messages();

274

275

return CompletableFuture.supplyAsync(() -> {

276

if (messages.size() > 10) {

277

// Summarize older messages, keep recent ones

278

List<String> recent = messages.subList(messages.size() - 5, messages.size());

279

String summary = "Summary of " + (messages.size() - 5) + " earlier messages: " +

280

messages.subList(0, messages.size() - 5).stream()

281

.collect(Collectors.joining(", "));

282

283

List<String> condensed = new ArrayList<>();

284

condensed.add(summary);

285

condensed.addAll(recent);

286

287

return Map.of("messages", condensed, "summarized", true);

288

}

289

290

return Map.of("summarized", false);

291

});

292

};

293

294

// Message validation

295

AsyncNodeAction<MessagesState<String>> messageValidator = (state) -> {

296

Optional<String> lastMsg = state.lastMessage();

297

298

return CompletableFuture.completedFuture(

299

lastMsg.map(msg -> {

300

boolean isValid = msg.length() > 0 && msg.length() <= 1000 &&

301

!msg.trim().isEmpty();

302

303

Map<String, Object> updates = new HashMap<>();

304

updates.put("last_message_valid", isValid);

305

306

if (!isValid) {

307

updates.put("messages", List.of("Please provide a valid message (1-1000 characters)"));

308

}

309

310

return updates;

311

}).orElse(Map.of("last_message_valid", false))

312

);

313

};

314

```

315

316

### Conversation Flow Management

317

318

Advanced patterns for managing conversational workflows.

319

320

```java { .api }

321

// Conversation state tracking

322

class ConversationState extends MessagesState<ChatMessage> {

323

public ConversationState(Map<String, Object> initData) {

324

super(initData);

325

}

326

327

public Optional<String> getCurrentTopic() {

328

return this.value("current_topic");

329

}

330

331

public Optional<Integer> getMessageCount() {

332

return Optional.of(messages().size());

333

}

334

335

public boolean hasRecentActivity() {

336

return lastMessage()

337

.map(msg -> System.currentTimeMillis() - msg.getTimestamp() < 300000) // 5 min

338

.orElse(false);

339

}

340

}

341

342

// Conversation management graph

343

MessagesStateGraph<ChatMessage> conversationGraph = new MessagesStateGraph<ChatMessage>() {

344

@Override

345

protected ConversationState getStateFactory() {

346

return ConversationState::new;

347

}

348

};

349

350

// Topic tracking node

351

conversationGraph.addNode("track_topic", (state) -> {

352

Optional<ChatMessage> lastMsg = state.lastMessage();

353

354

return CompletableFuture.supplyAsync(() -> {

355

String topic = "general";

356

357

if (lastMsg.isPresent()) {

358

String content = lastMsg.get().getContent().toLowerCase();

359

if (content.contains("weather")) topic = "weather";

360

else if (content.contains("food") || content.contains("recipe")) topic = "cooking";

361

else if (content.contains("help") || content.contains("support")) topic = "support";

362

}

363

364

return Map.of(

365

"current_topic", topic,

366

"topic_changed", !topic.equals(state.<String>value("current_topic").orElse("general"))

367

);

368

});

369

});

370

371

// Context-aware response generation

372

conversationGraph.addNode("contextual_response", (state) -> {

373

List<ChatMessage> messages = state.messages();

374

String currentTopic = state.<String>value("current_topic").orElse("general");

375

376

return CompletableFuture.supplyAsync(() -> {

377

// Generate response based on conversation context

378

String response = generateContextualResponse(messages, currentTopic);

379

ChatMessage aiResponse = new ChatMessage(response, "assistant");

380

381

return Map.of(

382

"messages", List.of(aiResponse),

383

"response_context", currentTopic

384

);

385

});

386

});

387

388

// Conversation cleanup

389

conversationGraph.addNode("cleanup_old_messages", (state) -> {

390

List<ChatMessage> messages = state.messages();

391

392

return CompletableFuture.completedFuture(

393

messages.size() > 50 ?

394

Map.of("messages", messages.subList(messages.size() - 30, messages.size())) :

395

Map.of("cleanup_performed", false)

396

);

397

});

398

399

private String generateContextualResponse(List<ChatMessage> messages, String topic) {

400

// Context-aware response generation logic

401

return "Response for topic '" + topic + "' based on " + messages.size() + " messages";

402

}

403

```

404

405

### Integration with Standard StateGraph

406

407

Combining MessagesState with regular StateGraph features.

408

409

```java { .api }

410

// Hybrid state combining messages with other data

411

class HybridState extends MessagesState<String> {

412

public HybridState(Map<String, Object> initData) {

413

super(initData);

414

}

415

416

public Optional<Integer> getScore() {

417

return this.value("score");

418

}

419

420

public Optional<String> getUserId() {

421

return this.value("user_id");

422

}

423

}

424

425

// Custom schema combining messages with other channels

426

Map<String, Channel<?>> hybridSchema = new HashMap<>(MessagesState.SCHEMA);

427

hybridSchema.put("score", (key, current, newVal) ->

428

Math.max((Integer) (current != null ? current : 0), (Integer) newVal));

429

hybridSchema.put("analytics", Channels.appender(ArrayList::new));

430

431

// Create graph with hybrid schema

432

StateGraph<HybridState> hybridGraph = new StateGraph<>(hybridSchema, HybridState::new);

433

434

hybridGraph.addNode("process_message_with_scoring", (state) -> {

435

Optional<String> lastMsg = state.lastMessage();

436

int currentScore = state.getScore().orElse(0);

437

438

return CompletableFuture.supplyAsync(() -> {

439

Map<String, Object> updates = new HashMap<>();

440

441

if (lastMsg.isPresent()) {

442

String msg = lastMsg.get();

443

updates.put("messages", List.of("Processed: " + msg));

444

445

// Calculate score based on message

446

int msgScore = msg.length() > 10 ? 10 : 5;

447

updates.put("score", msgScore);

448

449

// Add analytics event

450

updates.put("analytics", List.of(Map.of(

451

"event", "message_processed",

452

"score_delta", msgScore,

453

"timestamp", System.currentTimeMillis()

454

)));

455

}

456

457

return updates;

458

});

459

});

460

461

// Compile and use hybrid graph

462

CompiledGraph<HybridState> hybridApp = hybridGraph.compile();

463

Optional<HybridState> hybridResult = hybridApp.invoke(Map.of(

464

"messages", List.of("Hello hybrid world!"),

465

"user_id", "user123",

466

"score", 0

467

));

468

469

if (hybridResult.isPresent()) {

470

HybridState finalState = hybridResult.get();

471

System.out.println("Messages: " + finalState.messages());

472

System.out.println("Final score: " + finalState.getScore().orElse(0));

473

System.out.println("User: " + finalState.getUserId().orElse("unknown"));

474

}

475

```