Skip to main content

exo_consensus/
panel.rs

1// Copyright 2026 Exochain Foundation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at:
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// SPDX-License-Identifier: Apache-2.0
16
17use decision_forum::decision_object::DecisionClass;
18use serde::{Deserialize, Serialize};
19
20#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
21pub enum ModelProvider {
22    Anthropic,
23    OpenAI,
24    Google,
25    XAI,
26    Other(String),
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
30pub enum ModelRole {
31    Panelist,
32    DevilsAdvocate,
33    Synthesizer,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
37pub struct PanelModel {
38    pub model_id: String,
39    pub provider: ModelProvider,
40    pub role: ModelRole,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct Panel {
45    pub id: String,
46    pub models: Vec<PanelModel>,
47    pub max_rounds: u32,
48    pub convergence_threshold_bps: u64,
49    pub devil_advocate_model: Option<String>,
50}
51
52impl Panel {
53    /// Returns a sensible default panel configuration based on decision class.
54    pub fn default_panel(question_class: DecisionClass) -> Self {
55        match question_class {
56            DecisionClass::Routine => Panel {
57                id: "default-routine".into(),
58                models: vec![
59                    PanelModel {
60                        model_id: "claude-3-haiku".into(),
61                        provider: ModelProvider::Anthropic,
62                        role: ModelRole::Panelist,
63                    },
64                    PanelModel {
65                        model_id: "gpt-4o-mini".into(),
66                        provider: ModelProvider::OpenAI,
67                        role: ModelRole::Panelist,
68                    },
69                    PanelModel {
70                        model_id: "gemini-1.5-flash".into(),
71                        provider: ModelProvider::Google,
72                        role: ModelRole::Panelist,
73                    },
74                ],
75                max_rounds: 1,
76                convergence_threshold_bps: 6000,
77                devil_advocate_model: None,
78            },
79            DecisionClass::Operational => Panel {
80                id: "default-operational".into(),
81                models: vec![
82                    PanelModel {
83                        model_id: "claude-3-5-sonnet".into(),
84                        provider: ModelProvider::Anthropic,
85                        role: ModelRole::Panelist,
86                    },
87                    PanelModel {
88                        model_id: "gpt-4o".into(),
89                        provider: ModelProvider::OpenAI,
90                        role: ModelRole::Panelist,
91                    },
92                    PanelModel {
93                        model_id: "gemini-1.5-pro".into(),
94                        provider: ModelProvider::Google,
95                        role: ModelRole::Panelist,
96                    },
97                ],
98                max_rounds: 2,
99                convergence_threshold_bps: 7500,
100                devil_advocate_model: Some("gpt-4o".into()),
101            },
102            DecisionClass::Strategic => Panel {
103                id: "default-strategic".into(),
104                models: vec![
105                    PanelModel {
106                        model_id: "claude-3-opus".into(),
107                        provider: ModelProvider::Anthropic,
108                        role: ModelRole::Panelist,
109                    },
110                    PanelModel {
111                        model_id: "gpt-4o".into(),
112                        provider: ModelProvider::OpenAI,
113                        role: ModelRole::Panelist,
114                    },
115                    PanelModel {
116                        model_id: "gemini-1.5-pro".into(),
117                        provider: ModelProvider::Google,
118                        role: ModelRole::Panelist,
119                    },
120                    PanelModel {
121                        model_id: "grok-2".into(),
122                        provider: ModelProvider::XAI,
123                        role: ModelRole::Panelist,
124                    },
125                ],
126                max_rounds: 3,
127                convergence_threshold_bps: 8000,
128                devil_advocate_model: Some("claude-3-opus".into()),
129            },
130            DecisionClass::Constitutional => Panel {
131                id: "default-constitutional".into(),
132                models: vec![
133                    PanelModel {
134                        model_id: "claude-3-opus".into(),
135                        provider: ModelProvider::Anthropic,
136                        role: ModelRole::Panelist,
137                    },
138                    PanelModel {
139                        model_id: "gpt-4o".into(),
140                        provider: ModelProvider::OpenAI,
141                        role: ModelRole::Panelist,
142                    },
143                    PanelModel {
144                        model_id: "gemini-1.5-pro".into(),
145                        provider: ModelProvider::Google,
146                        role: ModelRole::Panelist,
147                    },
148                    PanelModel {
149                        model_id: "grok-2".into(),
150                        provider: ModelProvider::XAI,
151                        role: ModelRole::Panelist,
152                    },
153                    PanelModel {
154                        model_id: "o1-preview".into(),
155                        provider: ModelProvider::OpenAI,
156                        role: ModelRole::Panelist,
157                    },
158                ],
159                max_rounds: 4,
160                convergence_threshold_bps: 9000,
161                devil_advocate_model: Some("o1-preview".into()),
162            },
163        }
164    }
165}