cloudllm 0.6.2

A batteries-included Rust toolkit for building intelligent agents with LLM integration, multi-protocol tool support, and multi-agent orchestration.
Documentation
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
# Multi-Agent Council Tutorial: A Practical Cookbook

## Introduction

This tutorial demonstrates how to build multi-agent AI systems using CloudLLM's Council framework. We'll progress from simple to complex collaboration patterns, solving increasingly difficult problems with teams of AI agents from different providers (OpenAI, Claude, Gemini, Grok).

**The Challenge**: Throughout this tutorial, we'll tackle a pressing scientific problem: **designing an optimal carbon capture and storage (CCS) strategy** to combat climate change. This is a real-world problem with known solutions, allowing us to evaluate how well our AI councils converge on optimal approaches.

## Prerequisites

```rust
use cloudllm::{
    council::{Agent, Council, CouncilMode},
    clients::{
        openai::OpenAIClient,
        claude::ClaudeClient,
        gemini::GeminiClient,
        grok::GrokClient,
    },
};
use std::sync::Arc;

// Set your API keys
let openai_key = std::env::var("OPENAI_KEY").expect("OPENAI_KEY not set");
let anthropic_key = std::env::var("ANTHROPIC_KEY").expect("ANTHROPIC_KEY not set");
let gemini_key = std::env::var("GEMINI_KEY").expect("GEMINI_KEY not set");
let xai_key = std::env::var("XAI_KEY").expect("XAI_KEY not set");
```

---

## Recipe 1: Parallel Mode - Independent Expert Analysis

**Use Case**: When you need multiple independent perspectives on a problem without agents influencing each other.

**Problem**: Evaluate the three main carbon capture technologies: Direct Air Capture (DAC), Point Source Capture, and Ocean-based capture.

### The Council

```rust
async fn parallel_carbon_capture_analysis() -> Result<(), Box<dyn std::error::Error>> {
    // Create specialized agents with different AI providers
    let agent_chemistry = Agent::new(
        "chemistry-expert",
        "Dr. Chen (Chemistry Specialist)",
        Arc::new(ClaudeClient::new_with_model_str(
            &anthropic_key,
            "claude-3-5-sonnet-20241022"
        ))
    )
    .with_expertise("Chemical engineering, carbon chemistry, catalysis")
    .with_personality("Analytical, detail-oriented, focuses on molecular-level processes");

    let agent_economics = Agent::new(
        "economics-expert",
        "Dr. Martinez (Environmental Economist)",
        Arc::new(OpenAIClient::new_with_model_string(
            &openai_key,
            "gpt-4o"
        ))
    )
    .with_expertise("Cost-benefit analysis, carbon markets, policy economics")
    .with_personality("Pragmatic, data-driven, focuses on scalability and ROI");

    let agent_engineering = Agent::new(
        "engineering-expert",
        "Dr. Patel (Process Engineer)",
        Arc::new(GeminiClient::new_with_model_string(
            &gemini_key,
            "gemini-1.5-pro"
        ))
    )
    .with_expertise("Industrial processes, energy efficiency, systems integration")
    .with_personality("Practical, systems-thinking, focuses on implementation challenges");

    // Build the council
    let mut council = Council::new(
        "carbon-capture-council",
        "Carbon Capture Technology Assessment Council"
    )
    .with_mode(CouncilMode::Parallel)
    .with_system_context(
        "You are part of an expert panel evaluating carbon capture technologies. \
         Provide your independent analysis based on your domain expertise."
    );

    council.add_agent(agent_chemistry)?;
    council.add_agent(agent_economics)?;
    council.add_agent(agent_engineering)?;

    // Execute parallel analysis
    let response = council.discuss(
        "Analyze the three main carbon capture technologies (DAC, Point Source, Ocean-based) \
         and identify the most promising approach for immediate deployment. Consider: \
         1) Technical maturity, 2) Cost per ton CO2, 3) Scalability, 4) Environmental impact.",
        1  // One round
    ).await?;

    // Review results
    println!("=== PARALLEL ANALYSIS RESULTS ===\n");
    for msg in &response.messages {
        if let Some(name) = &msg.agent_name {
            println!("--- {} ---", name);
            println!("{}\n", msg.content);
        }
    }

    println!("Total tokens used: {}", response.total_tokens_used);

    Ok(())
}
```

**Expected Outcome**: Three independent analyses that can be compared side-by-side. Each expert provides their perspective without being influenced by others. Chemistry expert focuses on capture efficiency, economist on cost-effectiveness, engineer on practical deployment challenges.

**Best For**:
- Initial problem exploration
- Diverse viewpoint gathering
- Avoiding groupthink
- Fast parallel processing

---

## Recipe 2: Round-Robin Mode - Sequential Deliberation

**Use Case**: When agents should build upon each other's insights in a structured sequence.

**Problem**: Design a comprehensive carbon capture deployment strategy, where each expert adds their layer of analysis.

### The Council

```rust
async fn round_robin_deployment_strategy() -> Result<(), Box<dyn std::error::Error>> {
    // Create a 4-agent council with specific sequencing
    let agent_scientist = Agent::new(
        "climate-scientist",
        "Dr. Thompson (Climate Scientist)",
        Arc::new(ClaudeClient::new_with_model_str(
            &anthropic_key,
            "claude-3-5-sonnet-20241022"
        ))
    )
    .with_expertise("Climate modeling, carbon cycles, atmospheric science")
    .with_personality("Evidence-based, urgent but measured, focuses on climate impact");

    let agent_engineer = Agent::new(
        "systems-engineer",
        "Dr. Kim (Systems Engineer)",
        Arc::new(GeminiClient::new_with_model_string(
            &gemini_key,
            "gemini-1.5-pro"
        ))
    )
    .with_expertise("Large-scale infrastructure, grid integration, logistics")
    .with_personality("Methodical, risk-aware, focuses on feasibility");

    let agent_economist = Agent::new(
        "policy-economist",
        "Dr. Rodriguez (Policy & Economics)",
        Arc::new(OpenAIClient::new_with_model_string(
            &openai_key,
            "gpt-4o"
        ))
    )
    .with_expertise("Carbon pricing, government incentives, international cooperation")
    .with_personality("Strategic, diplomatic, focuses on policy mechanisms");

    let agent_innovator = Agent::new(
        "tech-innovator",
        "Dr. Zhang (Innovation Strategist)",
        Arc::new(GrokClient::new_with_model_str(
            &xai_key,
            "grok-beta"
        ))
    )
    .with_expertise("Emerging technologies, R&D acceleration, moonshot thinking")
    .with_personality("Optimistic, forward-thinking, challenges assumptions");

    let mut council = Council::new(
        "deployment-council",
        "Carbon Capture Deployment Strategy Council"
    )
    .with_mode(CouncilMode::RoundRobin)
    .with_system_context(
        "You are collaboratively designing a global carbon capture deployment strategy. \
         Build upon previous experts' insights while adding your unique perspective."
    );

    // Order matters in Round-Robin!
    council.add_agent(agent_scientist)?;  // Sets the scientific foundation
    council.add_agent(agent_engineer)?;   // Adds engineering reality
    council.add_agent(agent_economist)?;  // Layers in policy/economics
    council.add_agent(agent_innovator)?;  // Challenges with innovation

    // Run 2 rounds - each agent speaks twice
    let response = council.discuss(
        "Design a 10-year global deployment strategy for carbon capture to remove \
         5 gigatons CO2/year by 2035. Address: \
         1) Technology selection and phasing, \
         2) Infrastructure requirements, \
         3) Financing mechanisms, \
         4) Innovation acceleration.",
        2
    ).await?;

    // Display sequential discussion
    println!("=== ROUND-ROBIN STRATEGY DEVELOPMENT ===\n");
    let mut current_round = 0;
    for msg in &response.messages {
        if let Some(round_str) = msg.metadata.get("round") {
            let round: usize = round_str.parse().unwrap_or(0);
            if round != current_round {
                current_round = round;
                println!("\n╔════════════════════════════════════╗");
                println!("║         ROUND {}                    ║", round + 1);
                println!("╚════════════════════════════════════╝\n");
            }
        }

        if let Some(name) = &msg.agent_name {
            println!(">>> {} <<<", name);
            println!("{}\n", msg.content);
        }
    }

    println!("Total tokens used: {}", response.total_tokens_used);

    Ok(())
}
```

**Expected Outcome**: A layered, comprehensive strategy where each expert builds on the previous insights. Round 1 establishes the foundation, Round 2 refines and integrates. You'll see how Dr. Kim references Dr. Thompson's climate urgency, how Dr. Rodriguez builds financing around Kim's infrastructure needs, and how Dr. Zhang proposes innovations to accelerate the timeline.

**Best For**:
- Building complex, layered solutions
- Ensuring all perspectives are heard in order
- Creating comprehensive strategies
- Educational content (seeing reasoning progression)

---

## Recipe 3: Moderated Mode - Expert Panel with Chair

**Use Case**: When you have a moderator who should intelligently route questions to the most qualified expert.

**Problem**: Answer technical questions about carbon capture implementation, with a moderator selecting the right expert for each query.

### The Council

```rust
async fn moderated_qa_session() -> Result<(), Box<dyn std::error::Error>> {
    // Create the moderator
    let moderator = Agent::new(
        "moderator",
        "Dr. Sarah Wilson (Panel Chair)",
        Arc::new(OpenAIClient::new_with_model_string(
            &openai_key,
            "gpt-4o"
        ))
    )
    .with_expertise("Carbon capture overview, interdisciplinary coordination")
    .with_personality("Diplomatic, organized, excellent at matching questions to expertise");

    // Create specialized experts
    let agent_chemical = Agent::new(
        "chemical-expert",
        "Dr. Liu (Chemical Processes)",
        Arc::new(ClaudeClient::new_with_model_str(
            &anthropic_key,
            "claude-3-5-sonnet-20241022"
        ))
    )
    .with_expertise("Amine solvents, sorbent materials, reaction kinetics")
    .with_personality("Highly technical, precise with chemistry details");

    let agent_energy = Agent::new(
        "energy-expert",
        "Dr. Okafor (Energy Systems)",
        Arc::new(GeminiClient::new_with_model_string(
            &gemini_key,
            "gemini-1.5-pro"
        ))
    )
    .with_expertise("Energy requirements, heat integration, renewable coupling")
    .with_personality("Quantitative, focuses on energy efficiency and sustainability");

    let agent_storage = Agent::new(
        "storage-expert",
        "Dr. Bjorn (Geological Storage)",
        Arc::new(GrokClient::new_with_model_str(
            &xai_key,
            "grok-beta"
        ))
    )
    .with_expertise("CO2 sequestration, reservoir characterization, long-term monitoring")
    .with_personality("Safety-focused, experienced with subsurface engineering");

    let agent_lifecycle = Agent::new(
        "lifecycle-expert",
        "Dr. Sharma (Lifecycle Assessment)",
        Arc::new(OpenAIClient::new_with_model_string(
            &openai_key,
            "gpt-4o-mini"
        ))
    )
    .with_expertise("Full lifecycle analysis, net carbon accounting, environmental impact")
    .with_personality("Holistic thinker, considers entire system impacts");

    let mut council = Council::new(
        "moderated-qa-council",
        "Carbon Capture Q&A Panel"
    )
    .with_mode(CouncilMode::Moderated {
        moderator_id: "moderator".to_string()
    })
    .with_system_context(
        "You are participating in a technical Q&A session about carbon capture technology."
    );

    council.add_agent(moderator)?;
    council.add_agent(agent_chemical)?;
    council.add_agent(agent_energy)?;
    council.add_agent(agent_storage)?;
    council.add_agent(agent_lifecycle)?;

    // Ask a complex question requiring expert knowledge
    let response = council.discuss(
        "We're considering a 1 MT/year direct air capture facility powered by geothermal energy \
         in Iceland, storing CO2 in basalt formations. What are the key technical challenges and \
         is the net carbon balance truly negative when accounting for construction and operations?",
        3  // Let moderator route to 3 different experts
    ).await?;

    println!("=== MODERATED EXPERT Q&A ===\n");
    for msg in &response.messages {
        if let Some(name) = &msg.agent_name {
            if let Some(moderator_id) = msg.metadata.get("moderator") {
                println!("[Selected by {}]", moderator_id);
            }
            println!(">>> {} <<<", name);
            println!("{}\n", msg.content);
        }
    }

    println!("Total tokens used: {}", response.total_tokens_used);

    Ok(())
}
```

**Expected Outcome**: The moderator intelligently routes the multi-part question to appropriate experts. Energy expert discusses geothermal coupling, storage expert analyzes basalt mineralization potential, and lifecycle expert provides the net carbon accounting. The moderator may ask follow-ups to specific experts.

**Best For**:
- Q&A sessions
- Dynamic problem routing
- Efficient use of specialized expertise
- Interactive consultations

---

## Recipe 4: Hierarchical Mode - Multi-Layer Problem Solving

**Use Case**: When you need worker-level analysis, supervisor synthesis, and executive decision-making.

**Problem**: Evaluate and select the optimal carbon capture technology portfolio for three different regions with different constraints.

### The Council

```rust
async fn hierarchical_technology_selection() -> Result<(), Box<dyn std::error::Error>> {
    // === LAYER 1: Regional Analysis Workers ===

    let worker_north_america = Agent::new(
        "worker-na",
        "Analysis Team: North America",
        Arc::new(OpenAIClient::new_with_model_string(&openai_key, "gpt-4o-mini"))
    )
    .with_expertise("North American energy infrastructure, policy landscape, industrial base")
    .with_personality("Detail-oriented, region-specific knowledge");

    let worker_europe = Agent::new(
        "worker-eu",
        "Analysis Team: Europe",
        Arc::new(ClaudeClient::new_with_model_str(&anthropic_key, "claude-3-haiku-20240307"))
    )
    .with_expertise("European carbon markets, renewable integration, environmental regulations")
    .with_personality("Compliance-focused, sustainability-driven");

    let worker_asia = Agent::new(
        "worker-asia",
        "Analysis Team: Asia-Pacific",
        Arc::new(GeminiClient::new_with_model_string(&gemini_key, "gemini-1.5-flash"))
    )
    .with_expertise("Rapid industrialization, coal infrastructure, emerging technology adoption")
    .with_personality("Growth-oriented, pragmatic about constraints");

    // === LAYER 2: Domain Supervisors ===

    let supervisor_tech = Agent::new(
        "supervisor-tech",
        "Technical Supervisor",
        Arc::new(ClaudeClient::new_with_model_str(&anthropic_key, "claude-3-5-sonnet-20241022"))
    )
    .with_expertise("Technology assessment, comparative analysis, technical feasibility")
    .with_personality("Synthesizes technical details, identifies patterns across regions");

    let supervisor_business = Agent::new(
        "supervisor-business",
        "Business Supervisor",
        Arc::new(GeminiClient::new_with_model_string(&gemini_key, "gemini-1.5-pro"))
    )
    .with_expertise("Investment analysis, market dynamics, commercial viability")
    .with_personality("ROI-focused, risk assessment, market opportunities");

    // === LAYER 3: Executive Decision Maker ===

    let executive = Agent::new(
        "executive",
        "Chief Strategy Officer",
        Arc::new(OpenAIClient::new_with_model_string(&openai_key, "gpt-4o"))
    )
    .with_expertise("Strategic planning, portfolio management, resource allocation")
    .with_personality("Decisive, balances multiple objectives, long-term vision");

    let mut council = Council::new(
        "hierarchical-council",
        "Global Carbon Capture Portfolio Selection"
    )
    .with_mode(CouncilMode::Hierarchical {
        layers: vec![
            // Layer 1: Regional workers (parallel)
            vec![
                "worker-na".to_string(),
                "worker-eu".to_string(),
                "worker-asia".to_string(),
            ],
            // Layer 2: Domain supervisors (parallel)
            vec![
                "supervisor-tech".to_string(),
                "supervisor-business".to_string(),
            ],
            // Layer 3: Executive (single decision maker)
            vec!["executive".to_string()],
        ],
    })
    .with_system_context(
        "You are part of a hierarchical decision-making process for global carbon capture deployment."
    );

    // Add all agents
    council.add_agent(worker_north_america)?;
    council.add_agent(worker_europe)?;
    council.add_agent(worker_asia)?;
    council.add_agent(supervisor_tech)?;
    council.add_agent(supervisor_business)?;
    council.add_agent(executive)?;

    let response = council.discuss(
        "Evaluate carbon capture technology options for deployment in: \
         1) North America (abundant natural gas, existing industrial CO2 sources), \
         2) Europe (strong renewables, carbon pricing, limited storage), \
         3) Asia-Pacific (coal-heavy, rapid growth, cost sensitivity). \
         \
         Recommend a technology portfolio for each region that maximizes CO2 removal \
         while minimizing cost and risk. Consider: Point Source Capture, Direct Air Capture, \
         and Bioenergy with CCS (BECCS).",
        1
    ).await?;

    println!("=== HIERARCHICAL DECISION PROCESS ===\n");

    for msg in &response.messages {
        if let Some(layer_str) = msg.metadata.get("layer") {
            let layer: usize = layer_str.parse().unwrap_or(0);
            let layer_name = match layer {
                0 => "LAYER 1: Regional Analysis",
                1 => "LAYER 2: Domain Supervision",
                2 => "LAYER 3: Executive Decision",
                _ => "Unknown Layer",
            };

            println!("\n╔═══════════════════════════════════╗");
            println!("║  {}  ║", layer_name);
            println!("╚═══════════════════════════════════╝\n");
        }

        if let Some(name) = &msg.agent_name {
            println!(">>> {} <<<", name);
            println!("{}\n", msg.content);
        }
    }

    println!("Total tokens used: {}", response.total_tokens_used);

    Ok(())
}
```

**Expected Outcome**:
- **Layer 1**: Three regional teams provide detailed analysis of constraints and opportunities
- **Layer 2**: Supervisors synthesize the regional inputs - tech supervisor evaluates feasibility across regions, business supervisor assesses commercial viability
- **Layer 3**: Executive makes final portfolio allocation decision based on synthesized analysis

This mimics real organizational decision-making with clear information flow up the hierarchy.

**Best For**:
- Complex multi-region/multi-domain problems
- Organizational decision simulation
- Problems requiring both detail and synthesis
- Resource allocation decisions

---

## Recipe 5: Debate Mode - Adversarial Refinement with Convergence

**Use Case**: When you need agents to challenge each other's assumptions and converge on the most robust solution through argumentation.

**Problem**: Determine the optimal carbon price needed to make carbon capture economically viable. This is contentious with no single answer - perfect for debate.

### The Council

```rust
async fn debate_carbon_pricing() -> Result<(), Box<dyn std::error::Error>> {
    // Create agents with genuinely different perspectives

    let agent_market_optimist = Agent::new(
        "market-optimist",
        "Dr. Chen (Market Optimist)",
        Arc::new(OpenAIClient::new_with_model_string(&openai_key, "gpt-4o"))
    )
    .with_expertise("Market mechanisms, technological learning curves, innovation economics")
    .with_personality(
        "Believes in market efficiency and technology cost reductions. \
         Argues for moderate carbon prices with strong R&D support. \
         Optimistic about breakthrough technologies."
    );

    let agent_climate_hawk = Agent::new(
        "climate-hawk",
        "Dr. Andersson (Climate Emergency Advocate)",
        Arc::new(ClaudeClient::new_with_model_str(
            &anthropic_key,
            "claude-3-5-sonnet-20241022"
        ))
    )
    .with_expertise("Climate science, tipping points, urgency of action")
    .with_personality(
        "Emphasizes the urgency of climate crisis and social cost of carbon. \
         Advocates for high carbon prices to reflect true environmental cost. \
         Focuses on moral imperative and intergenerational justice."
    );

    let agent_pragmatist = Agent::new(
        "pragmatist",
        "Dr. Patel (Economic Pragmatist)",
        Arc::new(GeminiClient::new_with_model_string(&gemini_key, "gemini-1.5-pro"))
    )
    .with_expertise("Development economics, political feasibility, transition planning")
    .with_personality(
         "Balances climate urgency with economic reality and political feasibility. \
         Advocates for gradual, predictable carbon price escalation. \
         Concerned about economic disruption and public acceptance."
    );

    let agent_industry_realist = Agent::new(
        "industry-realist",
        "Dr. Mueller (Industrial Engineer)",
        Arc::new(GrokClient::new_with_model_str(&xai_key, "grok-beta"))
    )
    .with_expertise("Industrial processes, capital investment cycles, competitiveness")
    .with_personality(
        "Represents industry perspective and capital constraints. \
         Argues for carbon prices aligned with technology readiness and investment cycles. \
         Warns against policies that cause carbon leakage or economic damage."
    );

    let agent_systems_thinker = Agent::new(
        "systems-thinker",
        "Dr. Okonkwo (Systems Analyst)",
        Arc::new(OpenAIClient::new_with_model_string(&openai_key, "gpt-4o"))
    )
    .with_expertise("Systems dynamics, policy modeling, feedback loops")
    .with_personality(
        "Analyzes feedback loops and system effects. \
         Seeks carbon price that optimizes multiple objectives simultaneously. \
         Challenges simplistic arguments from all sides."
    );

    let mut council = Council::new(
        "debate-council",
        "Carbon Pricing Debate Council"
    )
    .with_mode(CouncilMode::Debate {
        max_rounds: 5,
        convergence_threshold: Some(0.65),  // 65% similarity triggers convergence
    })
    .with_system_context(
        "You are participating in a rigorous debate on carbon pricing policy. \
         Challenge weak arguments, acknowledge strong points, and refine your position \
         based on evidence presented by others. Seek truth through dialectic."
    );

    council.add_agent(agent_market_optimist)?;
    council.add_agent(agent_climate_hawk)?;
    council.add_agent(agent_pragmatist)?;
    council.add_agent(agent_industry_realist)?;
    council.add_agent(agent_systems_thinker)?;

    let response = council.discuss(
        "What carbon price ($/ton CO2) should be implemented globally to make carbon capture \
         and storage economically competitive while being politically and economically feasible? \
         \
         Consider: \
         - Current CCS costs ($50-150/ton depending on technology) \
         - Social cost of carbon ($50-200/ton depending on discount rate) \
         - Political feasibility and public acceptance \
         - Impact on industrial competitiveness \
         - Technology learning curves and R&D incentives \
         - Timeline for climate targets (net-zero by 2050) \
         \
         Justify your position with evidence and respond to counterarguments.",
        5
    ).await?;

    println!("=== CARBON PRICING DEBATE ===\n");

    let mut current_round = 0;
    for msg in &response.messages {
        if let Some(round_str) = msg.metadata.get("round") {
            let round: usize = round_str.parse().unwrap_or(0);
            if round != current_round {
                current_round = round;
                println!("\n");
                println!("╔═══════════════════════════════════════════════════╗");
                println!("║              DEBATE ROUND {}                       ║", round + 1);
                println!("╚═══════════════════════════════════════════════════╝");
                println!();
            }
        }

        if let Some(name) = &msg.agent_name {
            println!("┌─ {} ─┐", name);
            println!("{}", msg.content);
            println!("└─────────────────────────────────────────────────────┘\n");
        }
    }

    println!("\n=== DEBATE OUTCOME ===");
    println!("Rounds completed: {}", response.round);
    println!("Converged: {}", response.is_complete);
    if let Some(score) = response.convergence_score {
        println!("Convergence score: {:.2}%", score * 100.0);
    }
    println!("Total tokens used: {}", response.total_tokens_used);

    Ok(())
}
```

**Expected Outcome**:
- **Round 1**: Agents stake out initial positions ranging from $50-$200/ton
- **Round 2-3**: Agents challenge each other's assumptions. Climate hawk criticizes optimist's timeline, pragmatist questions hawk's political feasibility, industry realist highlights competitiveness concerns
- **Round 4-5**: Positions begin to converge as agents acknowledge valid points. May settle around $80-120/ton with gradual escalation
- **Convergence**: Debate terminates early if agents reach >65% similarity in their arguments

The debate mode is powerful because it surfaces and resolves conflicts through argumentation rather than averaging.

**Best For**:
- Contested decisions with no clear answer
- Exploring tradeoff spaces
- Stress-testing assumptions
- Finding robust consensus through dialectic

---

## Advanced: Combining Tools with Agents

All council modes support tool-augmented agents. Here's an example with real calculations:

```rust
use cloudllm::{
    tool_adapters::CustomToolAdapter,
    tool_protocol::{ToolRegistry, ToolMetadata, ToolParameter, ToolParameterType, ToolResult},
};

async fn council_with_tools() -> Result<(), Box<dyn std::error::Error>> {
    // Create a calculator tool for carbon accounting
    let mut adapter = CustomToolAdapter::new();

    adapter.register_tool(
        ToolMetadata::new("calculate_ccs_cost", "Calculate total cost of CCS deployment")
            .with_parameter(
                ToolParameter::new("capacity_mt_per_year", ToolParameterType::Number)
                    .with_description("Capture capacity in megatons CO2 per year")
                    .required()
            )
            .with_parameter(
                ToolParameter::new("cost_per_ton", ToolParameterType::Number)
                    .with_description("Cost per ton of CO2 captured")
                    .required()
            )
            .with_parameter(
                ToolParameter::new("years", ToolParameterType::Number)
                    .with_description("Number of years of operation")
                    .required()
            ),
        Arc::new(|params| {
            let capacity = params["capacity_mt_per_year"].as_f64().unwrap_or(0.0);
            let cost_per_ton = params["cost_per_ton"].as_f64().unwrap_or(0.0);
            let years = params["years"].as_f64().unwrap_or(0.0);

            let total_co2 = capacity * years;
            let total_cost = total_co2 * cost_per_ton * 1_000_000.0; // MT to tons
            let annual_cost = total_cost / years;

            Ok(ToolResult::success(serde_json::json!({
                "total_co2_removed_tons": total_co2 * 1_000_000.0,
                "total_cost_usd": total_cost,
                "annual_cost_usd": annual_cost,
                "cost_per_ton_usd": cost_per_ton
            })))
        })
    ).await;

    let registry = Arc::new(ToolRegistry::new(Arc::new(adapter)));

    // Create agent with tools
    let agent_analyst = Agent::new(
        "analyst",
        "Carbon Economics Analyst",
        Arc::new(OpenAIClient::new_with_model_string(&openai_key, "gpt-4o"))
    )
    .with_expertise("Carbon economics, cost analysis, financial modeling")
    .with_tools(registry);

    let mut council = Council::new("analysis-council", "CCS Cost Analysis")
        .with_mode(CouncilMode::Parallel);

    council.add_agent(agent_analyst)?;

    let response = council.discuss(
        "Calculate the total cost of deploying 5 MT/year carbon capture capacity \
         over 20 years at $100/ton. Use the calculate_ccs_cost tool.",
        1
    ).await?;

    println!("=== TOOL-AUGMENTED ANALYSIS ===\n");
    for msg in &response.messages {
        if let Some(name) = &msg.agent_name {
            println!("--- {} ---", name);
            println!("{}\n", msg.content);
        }
    }

    Ok(())
}
```

The agent will:
1. See the tool is available in its system prompt
2. Respond with: `{"tool_call": {"name": "calculate_ccs_cost", "parameters": {"capacity_mt_per_year": 5, "cost_per_ton": 100, "years": 20}}}`
3. Tool executes automatically
4. Agent receives result and formulates final response

---

## Best Practices

### 1. **Choosing the Right Mode**

| Mode | Use When | Avoid When |
|------|----------|-----------|
| **Parallel** | Need independent viewpoints, speed critical | Agents should build on each other |
| **RoundRobin** | Building layered solutions, clear expertise order | Need debate or routing |
| **Moderated** | Dynamic Q&A, varied question types | All questions suit same expert |
| **Hierarchical** | Complex multi-level problems, org simulation | Flat problem structure |
| **Debate** | Contested decisions, need robust consensus | Clear optimal solution exists |

### 2. **Agent Design Tips**

- **Expertise**: Be specific and actionable ("chemical kinetics of amine solvents" not "chemistry")
- **Personality**: Give distinct perspectives, not just different knowledge
- **Provider diversity**: Mix Claude (analytical), GPT-4 (balanced), Gemini (creative), Grok (contrarian)
- **Agent names**: Use realistic names and titles for better role-playing

### 3. **Prompt Engineering for Councils**

Good council prompts:
- ✅ Are specific and measurable
- ✅ Require multiple perspectives
- ✅ Have constrained solution spaces
- ✅ Provide context and constraints

Poor council prompts:
- ❌ Are too open-ended
- ❌ Can be answered by one expert
- ❌ Lack success criteria
- ❌ Are purely factual lookups

### 4. **Token Management**

```rust
// Monitor token usage
let response = council.discuss(prompt, rounds).await?;
println!("Tokens used: {}", response.total_tokens_used);

// For expensive debates, limit rounds
CouncilMode::Debate {
    max_rounds: 3,  // Lower for cost control
    convergence_threshold: Some(0.70)  // Higher = earlier convergence = lower cost
}
```

### 5. **Convergence Tuning**

The Jaccard similarity threshold controls debate termination:
- **0.50-0.60**: Very different positions can converge (loose consensus)
- **0.65-0.75**: Moderate agreement needed (recommended)
- **0.80-0.90**: Strong agreement needed (strict consensus)
- **0.95+**: Near-identical responses (potentially groupthink)

---

## Complete Example: Full Pipeline

Here's a complete program combining multiple modes:

```rust
use cloudllm::{
    council::{Agent, Council, CouncilMode},
    clients::{openai::OpenAIClient, claude::ClaudeClient, gemini::GeminiClient, grok::GrokClient},
};
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Load API keys
    let openai_key = std::env::var("OPENAI_KEY")?;
    let anthropic_key = std::env::var("ANTHROPIC_KEY")?;
    let gemini_key = std::env::var("GEMINI_KEY")?;
    let xai_key = std::env::var("XAI_KEY")?;

    println!("╔════════════════════════════════════════════════════════╗");
    println!("║  Carbon Capture Strategy: Multi-Mode Council Pipeline  ║");
    println!("╚════════════════════════════════════════════════════════╝\n");

    // STAGE 1: Parallel analysis of technologies
    println!("📊 STAGE 1: Independent Technology Assessment (Parallel Mode)\n");

    let mut stage1_council = Council::new("stage1", "Tech Assessment")
        .with_mode(CouncilMode::Parallel);

    stage1_council.add_agent(Agent::new(
        "tech1", "Technology Analyst A",
        Arc::new(ClaudeClient::new_with_model_str(&anthropic_key, "claude-3-5-sonnet-20241022"))
    ).with_expertise("Direct Air Capture"))?;

    stage1_council.add_agent(Agent::new(
        "tech2", "Technology Analyst B",
        Arc::new(OpenAIClient::new_with_model_string(&openai_key, "gpt-4o"))
    ).with_expertise("Point Source Capture"))?;

    let stage1_result = stage1_council.discuss(
        "Evaluate your assigned carbon capture technology. Provide: \
         1) Readiness level (TRL 1-9), 2) Current cost, 3) Key challenges.",
        1
    ).await?;

    for msg in &stage1_result.messages {
        if let Some(name) = &msg.agent_name {
            println!("✓ {}: {}\n", name, msg.content.chars().take(150).collect::<String>());
        }
    }

    // STAGE 2: Debate to select optimal approach
    println!("\n💬 STAGE 2: Technology Selection Debate (Debate Mode)\n");

    let mut stage2_council = Council::new("stage2", "Selection Debate")
        .with_mode(CouncilMode::Debate { max_rounds: 3, convergence_threshold: Some(0.70) });

    stage2_council.add_agent(Agent::new(
        "advocate1", "DAC Advocate",
        Arc::new(GeminiClient::new_with_model_string(&gemini_key, "gemini-1.5-pro"))
    ))?;

    stage2_council.add_agent(Agent::new(
        "advocate2", "Point Source Advocate",
        Arc::new(GrokClient::new_with_model_str(&xai_key, "grok-beta"))
    ))?;

    let stage2_result = stage2_council.discuss(
        "Based on the stage 1 assessment, argue for your preferred technology. \
         Consider cost, scalability, and timeline to 2035.",
        3
    ).await?;

    println!("Debate completed in {} rounds", stage2_result.round);
    if let Some(score) = stage2_result.convergence_score {
        println!("Convergence: {:.1}%\n", score * 100.0);
    }

    // STAGE 3: Hierarchical deployment planning
    println!("🏗️  STAGE 3: Deployment Strategy (Hierarchical Mode)\n");

    let mut stage3_council = Council::new("stage3", "Deployment Planning")
        .with_mode(CouncilMode::Hierarchical {
            layers: vec![
                vec!["regional1".to_string(), "regional2".to_string()],
                vec!["executive".to_string()],
            ],
        });

    stage3_council.add_agent(Agent::new(
        "regional1", "Regional Planner US",
        Arc::new(OpenAIClient::new_with_model_string(&openai_key, "gpt-4o-mini"))
    ))?;

    stage3_council.add_agent(Agent::new(
        "regional2", "Regional Planner EU",
        Arc::new(ClaudeClient::new_with_model_str(&anthropic_key, "claude-3-haiku-20240307"))
    ))?;

    stage3_council.add_agent(Agent::new(
        "executive", "Strategy Director",
        Arc::new(OpenAIClient::new_with_model_string(&openai_key, "gpt-4o"))
    ))?;

    let stage3_result = stage3_council.discuss(
        "Create a 5-year deployment roadmap for the selected technology \
         in US and EU markets. Executives synthesize into unified strategy.",
        1
    ).await?;

    println!("✓ Deployment strategy completed\n");

    // FINAL SUMMARY
    println!("╔════════════════════════════════════════╗");
    println!("║           PIPELINE COMPLETE             ║");
    println!("╚════════════════════════════════════════╝\n");

    let total_tokens = stage1_result.total_tokens_used
        + stage2_result.total_tokens_used
        + stage3_result.total_tokens_used;

    println!("Total tokens used: {}", total_tokens);
    println!("Estimated cost (GPT-4o): ${:.2}", (total_tokens as f64) * 0.00001);

    Ok(())
}
```

---

## Troubleshooting

### Problem: Agents give similar responses
**Solution**: Increase personality/perspective differences, use different model providers, add expertise specificity

### Problem: Debate doesn't converge
**Solution**: Lower convergence threshold, increase max_rounds, or ensure agents have common ground

### Problem: High token costs
**Solution**: Use smaller models for workers, limit debate rounds, use parallel instead of round-robin for independent tasks

### Problem: Agents ignore each other in Round-Robin
**Solution**: Strengthen system context to emphasize building on previous responses, increase rounds

---

## Conclusion

You now have five powerful patterns for multi-agent collaboration:

1. **Parallel**: Fast, independent analysis
2. **RoundRobin**: Sequential, layered deliberation
3. **Moderated**: Dynamic expert routing
4. **Hierarchical**: Multi-level organizational decision-making
5. **Debate**: Adversarial convergence on robust solutions

Each mode excels in different scenarios. The carbon capture examples demonstrate how these patterns can tackle complex, real-world problems requiring multiple perspectives and deep domain expertise.

**Next Steps**:
- Experiment with agent personality variations
- Add custom tools for domain-specific calculations
- Combine modes in multi-stage pipelines
- Try other pressing problems: pandemic response, space mission planning, economic policy, etc.

Happy orchestrating! 🤖🤝🤖