klaude-code 1.2.6__py3-none-any.whl → 1.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. klaude_code/auth/__init__.py +24 -0
  2. klaude_code/auth/codex/__init__.py +20 -0
  3. klaude_code/auth/codex/exceptions.py +17 -0
  4. klaude_code/auth/codex/jwt_utils.py +45 -0
  5. klaude_code/auth/codex/oauth.py +229 -0
  6. klaude_code/auth/codex/token_manager.py +84 -0
  7. klaude_code/cli/auth_cmd.py +73 -0
  8. klaude_code/cli/config_cmd.py +91 -0
  9. klaude_code/cli/cost_cmd.py +338 -0
  10. klaude_code/cli/debug.py +78 -0
  11. klaude_code/cli/list_model.py +307 -0
  12. klaude_code/cli/main.py +233 -134
  13. klaude_code/cli/runtime.py +309 -117
  14. klaude_code/{version.py → cli/self_update.py} +114 -5
  15. klaude_code/cli/session_cmd.py +37 -21
  16. klaude_code/command/__init__.py +88 -27
  17. klaude_code/command/clear_cmd.py +8 -7
  18. klaude_code/command/command_abc.py +31 -31
  19. klaude_code/command/debug_cmd.py +79 -0
  20. klaude_code/command/export_cmd.py +19 -53
  21. klaude_code/command/export_online_cmd.py +154 -0
  22. klaude_code/command/fork_session_cmd.py +267 -0
  23. klaude_code/command/help_cmd.py +7 -8
  24. klaude_code/command/model_cmd.py +60 -10
  25. klaude_code/command/model_select.py +84 -0
  26. klaude_code/command/prompt-jj-describe.md +32 -0
  27. klaude_code/command/prompt_command.py +19 -11
  28. klaude_code/command/refresh_cmd.py +8 -10
  29. klaude_code/command/registry.py +139 -40
  30. klaude_code/command/release_notes_cmd.py +84 -0
  31. klaude_code/command/resume_cmd.py +111 -0
  32. klaude_code/command/status_cmd.py +104 -60
  33. klaude_code/command/terminal_setup_cmd.py +7 -9
  34. klaude_code/command/thinking_cmd.py +98 -0
  35. klaude_code/config/__init__.py +14 -6
  36. klaude_code/config/assets/__init__.py +1 -0
  37. klaude_code/config/assets/builtin_config.yaml +303 -0
  38. klaude_code/config/builtin_config.py +38 -0
  39. klaude_code/config/config.py +378 -109
  40. klaude_code/config/select_model.py +117 -53
  41. klaude_code/config/thinking.py +269 -0
  42. klaude_code/{const/__init__.py → const.py} +50 -19
  43. klaude_code/core/agent.py +20 -28
  44. klaude_code/core/executor.py +327 -112
  45. klaude_code/core/manager/__init__.py +2 -4
  46. klaude_code/core/manager/llm_clients.py +1 -15
  47. klaude_code/core/manager/llm_clients_builder.py +10 -11
  48. klaude_code/core/manager/sub_agent_manager.py +37 -6
  49. klaude_code/core/prompt.py +63 -44
  50. klaude_code/core/prompts/prompt-claude-code.md +2 -13
  51. klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +117 -0
  52. klaude_code/core/prompts/prompt-codex-gpt-5-2-codex.md +117 -0
  53. klaude_code/core/prompts/prompt-codex.md +9 -42
  54. klaude_code/core/prompts/prompt-minimal.md +12 -0
  55. klaude_code/core/prompts/{prompt-subagent-explore.md → prompt-sub-agent-explore.md} +16 -3
  56. klaude_code/core/prompts/{prompt-subagent-oracle.md → prompt-sub-agent-oracle.md} +1 -2
  57. klaude_code/core/prompts/prompt-sub-agent-web.md +51 -0
  58. klaude_code/core/reminders.py +283 -95
  59. klaude_code/core/task.py +113 -75
  60. klaude_code/core/tool/__init__.py +24 -31
  61. klaude_code/core/tool/file/_utils.py +36 -0
  62. klaude_code/core/tool/file/apply_patch.py +17 -25
  63. klaude_code/core/tool/file/apply_patch_tool.py +57 -77
  64. klaude_code/core/tool/file/diff_builder.py +151 -0
  65. klaude_code/core/tool/file/edit_tool.py +50 -63
  66. klaude_code/core/tool/file/move_tool.md +41 -0
  67. klaude_code/core/tool/file/move_tool.py +435 -0
  68. klaude_code/core/tool/file/read_tool.md +1 -1
  69. klaude_code/core/tool/file/read_tool.py +86 -86
  70. klaude_code/core/tool/file/write_tool.py +59 -69
  71. klaude_code/core/tool/report_back_tool.py +84 -0
  72. klaude_code/core/tool/shell/bash_tool.py +265 -22
  73. klaude_code/core/tool/shell/command_safety.py +3 -6
  74. klaude_code/core/tool/{memory → skill}/skill_tool.py +16 -26
  75. klaude_code/core/tool/sub_agent_tool.py +13 -2
  76. klaude_code/core/tool/todo/todo_write_tool.md +0 -157
  77. klaude_code/core/tool/todo/todo_write_tool.py +1 -1
  78. klaude_code/core/tool/todo/todo_write_tool_raw.md +182 -0
  79. klaude_code/core/tool/todo/update_plan_tool.py +1 -1
  80. klaude_code/core/tool/tool_abc.py +18 -0
  81. klaude_code/core/tool/tool_context.py +27 -12
  82. klaude_code/core/tool/tool_registry.py +7 -7
  83. klaude_code/core/tool/tool_runner.py +44 -36
  84. klaude_code/core/tool/truncation.py +29 -14
  85. klaude_code/core/tool/web/mermaid_tool.md +43 -0
  86. klaude_code/core/tool/web/mermaid_tool.py +2 -5
  87. klaude_code/core/tool/web/web_fetch_tool.md +1 -1
  88. klaude_code/core/tool/web/web_fetch_tool.py +112 -22
  89. klaude_code/core/tool/web/web_search_tool.md +23 -0
  90. klaude_code/core/tool/web/web_search_tool.py +130 -0
  91. klaude_code/core/turn.py +168 -66
  92. klaude_code/llm/__init__.py +2 -10
  93. klaude_code/llm/anthropic/client.py +190 -178
  94. klaude_code/llm/anthropic/input.py +39 -15
  95. klaude_code/llm/bedrock/__init__.py +3 -0
  96. klaude_code/llm/bedrock/client.py +60 -0
  97. klaude_code/llm/client.py +7 -21
  98. klaude_code/llm/codex/__init__.py +5 -0
  99. klaude_code/llm/codex/client.py +149 -0
  100. klaude_code/llm/google/__init__.py +3 -0
  101. klaude_code/llm/google/client.py +309 -0
  102. klaude_code/llm/google/input.py +215 -0
  103. klaude_code/llm/input_common.py +3 -9
  104. klaude_code/llm/openai_compatible/client.py +72 -164
  105. klaude_code/llm/openai_compatible/input.py +6 -4
  106. klaude_code/llm/openai_compatible/stream.py +273 -0
  107. klaude_code/llm/openai_compatible/tool_call_accumulator.py +17 -1
  108. klaude_code/llm/openrouter/client.py +89 -160
  109. klaude_code/llm/openrouter/input.py +18 -30
  110. klaude_code/llm/openrouter/reasoning.py +118 -0
  111. klaude_code/llm/registry.py +39 -7
  112. klaude_code/llm/responses/client.py +184 -171
  113. klaude_code/llm/responses/input.py +20 -1
  114. klaude_code/llm/usage.py +17 -12
  115. klaude_code/protocol/commands.py +17 -1
  116. klaude_code/protocol/events.py +31 -4
  117. klaude_code/protocol/llm_param.py +13 -10
  118. klaude_code/protocol/model.py +232 -29
  119. klaude_code/protocol/op.py +90 -1
  120. klaude_code/protocol/op_handler.py +35 -1
  121. klaude_code/protocol/sub_agent/__init__.py +117 -0
  122. klaude_code/protocol/sub_agent/explore.py +63 -0
  123. klaude_code/protocol/sub_agent/oracle.py +91 -0
  124. klaude_code/protocol/sub_agent/task.py +61 -0
  125. klaude_code/protocol/sub_agent/web.py +79 -0
  126. klaude_code/protocol/tools.py +4 -2
  127. klaude_code/session/__init__.py +2 -2
  128. klaude_code/session/codec.py +71 -0
  129. klaude_code/session/export.py +293 -86
  130. klaude_code/session/selector.py +89 -67
  131. klaude_code/session/session.py +320 -309
  132. klaude_code/session/store.py +220 -0
  133. klaude_code/session/templates/export_session.html +595 -83
  134. klaude_code/session/templates/mermaid_viewer.html +926 -0
  135. klaude_code/skill/__init__.py +27 -0
  136. klaude_code/skill/assets/deslop/SKILL.md +17 -0
  137. klaude_code/skill/assets/dev-docs/SKILL.md +108 -0
  138. klaude_code/skill/assets/handoff/SKILL.md +39 -0
  139. klaude_code/skill/assets/jj-workspace/SKILL.md +20 -0
  140. klaude_code/skill/assets/skill-creator/SKILL.md +139 -0
  141. klaude_code/{core/tool/memory/skill_loader.py → skill/loader.py} +55 -15
  142. klaude_code/skill/manager.py +70 -0
  143. klaude_code/skill/system_skills.py +192 -0
  144. klaude_code/trace/__init__.py +20 -2
  145. klaude_code/trace/log.py +150 -5
  146. klaude_code/ui/__init__.py +4 -9
  147. klaude_code/ui/core/input.py +1 -1
  148. klaude_code/ui/core/stage_manager.py +7 -7
  149. klaude_code/ui/modes/debug/display.py +2 -1
  150. klaude_code/ui/modes/repl/__init__.py +3 -48
  151. klaude_code/ui/modes/repl/clipboard.py +5 -5
  152. klaude_code/ui/modes/repl/completers.py +487 -123
  153. klaude_code/ui/modes/repl/display.py +5 -4
  154. klaude_code/ui/modes/repl/event_handler.py +370 -117
  155. klaude_code/ui/modes/repl/input_prompt_toolkit.py +552 -105
  156. klaude_code/ui/modes/repl/key_bindings.py +146 -23
  157. klaude_code/ui/modes/repl/renderer.py +189 -99
  158. klaude_code/ui/renderers/assistant.py +9 -2
  159. klaude_code/ui/renderers/bash_syntax.py +178 -0
  160. klaude_code/ui/renderers/common.py +78 -0
  161. klaude_code/ui/renderers/developer.py +104 -48
  162. klaude_code/ui/renderers/diffs.py +87 -6
  163. klaude_code/ui/renderers/errors.py +11 -6
  164. klaude_code/ui/renderers/mermaid_viewer.py +57 -0
  165. klaude_code/ui/renderers/metadata.py +112 -76
  166. klaude_code/ui/renderers/sub_agent.py +92 -7
  167. klaude_code/ui/renderers/thinking.py +40 -18
  168. klaude_code/ui/renderers/tools.py +405 -227
  169. klaude_code/ui/renderers/user_input.py +73 -13
  170. klaude_code/ui/rich/__init__.py +10 -1
  171. klaude_code/ui/rich/cjk_wrap.py +228 -0
  172. klaude_code/ui/rich/code_panel.py +131 -0
  173. klaude_code/ui/rich/live.py +17 -0
  174. klaude_code/ui/rich/markdown.py +305 -170
  175. klaude_code/ui/rich/searchable_text.py +10 -13
  176. klaude_code/ui/rich/status.py +190 -49
  177. klaude_code/ui/rich/theme.py +135 -39
  178. klaude_code/ui/terminal/__init__.py +55 -0
  179. klaude_code/ui/terminal/color.py +1 -1
  180. klaude_code/ui/terminal/control.py +13 -22
  181. klaude_code/ui/terminal/notifier.py +44 -4
  182. klaude_code/ui/terminal/selector.py +658 -0
  183. klaude_code/ui/utils/common.py +0 -18
  184. klaude_code-1.8.0.dist-info/METADATA +377 -0
  185. klaude_code-1.8.0.dist-info/RECORD +219 -0
  186. {klaude_code-1.2.6.dist-info → klaude_code-1.8.0.dist-info}/entry_points.txt +1 -0
  187. klaude_code/command/diff_cmd.py +0 -138
  188. klaude_code/command/prompt-dev-docs-update.md +0 -56
  189. klaude_code/command/prompt-dev-docs.md +0 -46
  190. klaude_code/config/list_model.py +0 -162
  191. klaude_code/core/manager/agent_manager.py +0 -127
  192. klaude_code/core/prompts/prompt-subagent-webfetch.md +0 -46
  193. klaude_code/core/tool/file/multi_edit_tool.md +0 -42
  194. klaude_code/core/tool/file/multi_edit_tool.py +0 -199
  195. klaude_code/core/tool/memory/memory_tool.md +0 -16
  196. klaude_code/core/tool/memory/memory_tool.py +0 -462
  197. klaude_code/llm/openrouter/reasoning_handler.py +0 -209
  198. klaude_code/protocol/sub_agent.py +0 -348
  199. klaude_code/ui/utils/debouncer.py +0 -42
  200. klaude_code-1.2.6.dist-info/METADATA +0 -178
  201. klaude_code-1.2.6.dist-info/RECORD +0 -167
  202. /klaude_code/core/prompts/{prompt-subagent.md → prompt-sub-agent.md} +0 -0
  203. /klaude_code/core/tool/{memory → skill}/__init__.py +0 -0
  204. /klaude_code/core/tool/{memory → skill}/skill_tool.md +0 -0
  205. {klaude_code-1.2.6.dist-info → klaude_code-1.8.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,307 @@
1
+ import datetime
2
+
3
+ from rich.console import Console, Group
4
+ from rich.panel import Panel
5
+ from rich.table import Table
6
+ from rich.text import Text
7
+
8
+ from klaude_code.config import Config
9
+ from klaude_code.config.config import ModelConfig, ProviderConfig, parse_env_var_syntax
10
+ from klaude_code.protocol.llm_param import LLMClientProtocol
11
+ from klaude_code.protocol.sub_agent import iter_sub_agent_profiles
12
+ from klaude_code.ui.rich.theme import ThemeKey, get_theme
13
+
14
+
15
+ def _get_codex_status_elements() -> list[Text]:
16
+ """Get Codex OAuth login status as Text elements for panel display."""
17
+ from klaude_code.auth.codex.token_manager import CodexTokenManager
18
+
19
+ elements: list[Text] = []
20
+ token_manager = CodexTokenManager()
21
+ state = token_manager.get_state()
22
+
23
+ if state is None:
24
+ elements.append(
25
+ Text.assemble(
26
+ ("Status: ", "bold"),
27
+ ("Not logged in", ThemeKey.CONFIG_STATUS_ERROR),
28
+ (" (run 'klaude login codex' to authenticate)", "dim"),
29
+ )
30
+ )
31
+ elif state.is_expired():
32
+ elements.append(
33
+ Text.assemble(
34
+ ("Status: ", "bold"),
35
+ ("Token expired", ThemeKey.CONFIG_STATUS_ERROR),
36
+ (" (run 'klaude login codex' to re-authenticate)", "dim"),
37
+ )
38
+ )
39
+ else:
40
+ expires_dt = datetime.datetime.fromtimestamp(state.expires_at, tz=datetime.UTC)
41
+ elements.append(
42
+ Text.assemble(
43
+ ("Status: ", "bold"),
44
+ ("Logged in", ThemeKey.CONFIG_STATUS_OK),
45
+ (f" (account: {state.account_id[:8]}..., expires: {expires_dt.strftime('%Y-%m-%d %H:%M UTC')})", "dim"),
46
+ )
47
+ )
48
+
49
+ elements.append(
50
+ Text.assemble(
51
+ ("Visit ", "dim"),
52
+ (
53
+ "https://chatgpt.com/codex/settings/usage",
54
+ "blue underline link https://chatgpt.com/codex/settings/usage",
55
+ ),
56
+ (" for up-to-date information on rate limits and credits", "dim"),
57
+ )
58
+ )
59
+ return elements
60
+
61
+
62
+ def mask_api_key(api_key: str | None) -> str:
63
+ """Mask API key to show only first 6 and last 6 characters with *** in between"""
64
+ if not api_key or api_key == "N/A":
65
+ return "N/A"
66
+
67
+ if len(api_key) <= 12:
68
+ return api_key
69
+
70
+ return f"{api_key[:6]} … {api_key[-6:]}"
71
+
72
+
73
+ def format_api_key_display(provider: ProviderConfig) -> Text:
74
+ """Format API key display with warning if env var is not set."""
75
+ env_var = provider.get_api_key_env_var()
76
+ resolved_key = provider.get_resolved_api_key()
77
+
78
+ if env_var:
79
+ # Using ${ENV_VAR} syntax
80
+ if resolved_key:
81
+ return Text.assemble(
82
+ (f"${{{env_var}}} = ", "dim"),
83
+ (mask_api_key(resolved_key), ""),
84
+ )
85
+ else:
86
+ return Text.assemble(
87
+ (f"${{{env_var}}} ", ""),
88
+ ("(not set)", ThemeKey.CONFIG_STATUS_ERROR),
89
+ )
90
+ elif provider.api_key:
91
+ # Plain API key
92
+ return Text(mask_api_key(provider.api_key))
93
+ else:
94
+ return Text("N/A")
95
+
96
+
97
+ def format_env_var_display(value: str | None) -> Text:
98
+ """Format environment variable display with warning if not set."""
99
+ env_var, resolved = parse_env_var_syntax(value)
100
+
101
+ if env_var:
102
+ # Using ${ENV_VAR} syntax
103
+ if resolved:
104
+ return Text.assemble(
105
+ (f"${{{env_var}}} = ", "dim"),
106
+ (mask_api_key(resolved), ""),
107
+ )
108
+ else:
109
+ return Text.assemble(
110
+ (f"${{{env_var}}} ", ""),
111
+ ("(not set)", ThemeKey.CONFIG_STATUS_ERROR),
112
+ )
113
+ elif value:
114
+ # Plain value
115
+ return Text(mask_api_key(value))
116
+ else:
117
+ return Text("N/A")
118
+
119
+
120
+ def _get_model_params_display(model: ModelConfig) -> list[Text]:
121
+ """Get display elements for model parameters."""
122
+ params: list[Text] = []
123
+ if model.model_params.thinking:
124
+ if model.model_params.thinking.reasoning_effort is not None:
125
+ params.append(
126
+ Text.assemble(
127
+ ("reason-effort", ThemeKey.CONFIG_PARAM_LABEL),
128
+ ": ",
129
+ model.model_params.thinking.reasoning_effort,
130
+ )
131
+ )
132
+ if model.model_params.thinking.reasoning_summary is not None:
133
+ params.append(
134
+ Text.assemble(
135
+ ("reason-summary", ThemeKey.CONFIG_PARAM_LABEL),
136
+ ": ",
137
+ model.model_params.thinking.reasoning_summary,
138
+ )
139
+ )
140
+ if model.model_params.thinking.budget_tokens is not None:
141
+ params.append(
142
+ Text.assemble(
143
+ ("thinking-budget-tokens", ThemeKey.CONFIG_PARAM_LABEL),
144
+ ": ",
145
+ str(model.model_params.thinking.budget_tokens),
146
+ )
147
+ )
148
+ if model.model_params.provider_routing:
149
+ params.append(
150
+ Text.assemble(
151
+ ("provider-routing", ThemeKey.CONFIG_PARAM_LABEL),
152
+ ": ",
153
+ model.model_params.provider_routing.model_dump_json(exclude_none=True),
154
+ )
155
+ )
156
+ if len(params) == 0:
157
+ params.append(Text("N/A", style=ThemeKey.CONFIG_PARAM_LABEL))
158
+ return params
159
+
160
+
161
+ def display_models_and_providers(config: Config):
162
+ """Display models and providers configuration using rich formatting"""
163
+ themes = get_theme(config.theme)
164
+ console = Console(theme=themes.app_theme)
165
+
166
+ # Display each provider as a separate panel
167
+ for provider in config.provider_list:
168
+ # Provider info section
169
+ provider_info = Table.grid(padding=(0, 1))
170
+ provider_info.add_column(width=12)
171
+ provider_info.add_column()
172
+
173
+ provider_info.add_row(
174
+ Text("Protocol:", style=ThemeKey.CONFIG_PARAM_LABEL),
175
+ Text(provider.protocol.value),
176
+ )
177
+ if provider.base_url:
178
+ provider_info.add_row(
179
+ Text("Base URL:", style=ThemeKey.CONFIG_PARAM_LABEL),
180
+ Text(provider.base_url or "N/A"),
181
+ )
182
+ if provider.api_key:
183
+ provider_info.add_row(
184
+ Text("API Key:", style=ThemeKey.CONFIG_PARAM_LABEL),
185
+ format_api_key_display(provider),
186
+ )
187
+
188
+ # AWS Bedrock parameters
189
+ if provider.protocol == LLMClientProtocol.BEDROCK:
190
+ if provider.aws_access_key:
191
+ provider_info.add_row(
192
+ Text("AWS Key:", style=ThemeKey.CONFIG_PARAM_LABEL),
193
+ format_env_var_display(provider.aws_access_key),
194
+ )
195
+ if provider.aws_secret_key:
196
+ provider_info.add_row(
197
+ Text("AWS Secret:", style=ThemeKey.CONFIG_PARAM_LABEL),
198
+ format_env_var_display(provider.aws_secret_key),
199
+ )
200
+ if provider.aws_region:
201
+ provider_info.add_row(
202
+ Text("AWS Region:", style=ThemeKey.CONFIG_PARAM_LABEL),
203
+ format_env_var_display(provider.aws_region),
204
+ )
205
+ if provider.aws_session_token:
206
+ provider_info.add_row(
207
+ Text("AWS Token:", style=ThemeKey.CONFIG_PARAM_LABEL),
208
+ format_env_var_display(provider.aws_session_token),
209
+ )
210
+ if provider.aws_profile:
211
+ provider_info.add_row(
212
+ Text("AWS Profile:", style=ThemeKey.CONFIG_PARAM_LABEL),
213
+ format_env_var_display(provider.aws_profile),
214
+ )
215
+
216
+ # Check if provider has valid API key
217
+ provider_available = not provider.is_api_key_missing()
218
+
219
+ # Models table for this provider
220
+ models_table = Table.grid(padding=(0, 1), expand=True)
221
+ models_table.add_column(width=2, no_wrap=True) # Status
222
+ models_table.add_column(overflow="fold", ratio=2) # Name
223
+ models_table.add_column(overflow="fold", ratio=3) # Model
224
+ models_table.add_column(overflow="fold", ratio=4) # Params
225
+
226
+ # Add header
227
+ models_table.add_row(
228
+ Text("", style="bold"),
229
+ Text("Name", style=ThemeKey.CONFIG_TABLE_HEADER),
230
+ Text("Model", style=ThemeKey.CONFIG_TABLE_HEADER),
231
+ Text("Params", style=ThemeKey.CONFIG_TABLE_HEADER),
232
+ )
233
+
234
+ # Add models for this provider
235
+ for model in provider.model_list:
236
+ if not provider_available:
237
+ # Provider API key not set - show as unavailable
238
+ status = Text("-", style="dim")
239
+ name = Text(model.model_name, style="dim")
240
+ model_id = Text(model.model_params.model or "N/A", style="dim")
241
+ params = [Text("(unavailable)", style="dim")]
242
+ elif model.model_name == config.main_model:
243
+ status = Text("★", style=ThemeKey.CONFIG_STATUS_PRIMARY)
244
+ name = Text(model.model_name, style=ThemeKey.CONFIG_STATUS_PRIMARY)
245
+ model_id = Text(model.model_params.model or "N/A", style="")
246
+ params = _get_model_params_display(model)
247
+ else:
248
+ status = Text("✔", style=ThemeKey.CONFIG_STATUS_OK)
249
+ name = Text(model.model_name, style=ThemeKey.CONFIG_ITEM_NAME)
250
+ model_id = Text(model.model_params.model or "N/A", style="")
251
+ params = _get_model_params_display(model)
252
+
253
+ models_table.add_row(status, name, model_id, Group(*params))
254
+
255
+ # Create panel content with provider info and models
256
+ panel_elements = [
257
+ provider_info,
258
+ Text(""), # Spacer
259
+ Text("Models:", style=ThemeKey.CONFIG_TABLE_HEADER),
260
+ models_table,
261
+ ]
262
+
263
+ # Add Codex status if this is a codex provider
264
+ if provider.protocol == LLMClientProtocol.CODEX:
265
+ panel_elements.append(Text("")) # Spacer
266
+ panel_elements.extend(_get_codex_status_elements())
267
+
268
+ panel_content = Group(*panel_elements)
269
+
270
+ panel = Panel(
271
+ panel_content,
272
+ title=Text(f"Provider: {provider.provider_name}", style=ThemeKey.CONFIG_PROVIDER),
273
+ border_style=ThemeKey.CONFIG_PANEL_BORDER,
274
+ padding=(0, 1),
275
+ title_align="left",
276
+ )
277
+
278
+ console.print(panel)
279
+ console.print()
280
+
281
+ # Display main model info
282
+ console.print()
283
+ if config.main_model:
284
+ console.print(
285
+ Text.assemble(
286
+ ("Default Model: ", "bold"),
287
+ (config.main_model, ThemeKey.CONFIG_STATUS_PRIMARY),
288
+ )
289
+ )
290
+ else:
291
+ console.print(
292
+ Text.assemble(
293
+ ("Default Model: ", "bold"),
294
+ ("(not set)", ThemeKey.CONFIG_STATUS_ERROR),
295
+ )
296
+ )
297
+
298
+ for profile in iter_sub_agent_profiles():
299
+ sub_model_name = config.sub_agent_models.get(profile.name)
300
+ if not sub_model_name:
301
+ continue
302
+ console.print(
303
+ Text.assemble(
304
+ (f"{profile.name} Model: ", "bold"),
305
+ (sub_model_name, ThemeKey.CONFIG_STATUS_PRIMARY),
306
+ )
307
+ )