klaude-code 1.2.25__py3-none-any.whl → 1.2.27__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.
- klaude_code/cli/config_cmd.py +1 -5
- klaude_code/cli/list_model.py +170 -129
- klaude_code/cli/main.py +37 -5
- klaude_code/cli/runtime.py +4 -6
- klaude_code/cli/self_update.py +2 -1
- klaude_code/cli/session_cmd.py +1 -1
- klaude_code/config/__init__.py +3 -1
- klaude_code/config/assets/__init__.py +1 -0
- klaude_code/config/assets/builtin_config.yaml +233 -0
- klaude_code/config/builtin_config.py +37 -0
- klaude_code/config/config.py +332 -112
- klaude_code/config/select_model.py +45 -8
- klaude_code/const.py +5 -1
- klaude_code/core/executor.py +4 -2
- klaude_code/core/manager/llm_clients_builder.py +4 -1
- klaude_code/core/tool/file/apply_patch_tool.py +26 -3
- klaude_code/core/tool/file/edit_tool.py +4 -4
- klaude_code/core/tool/file/write_tool.py +4 -4
- klaude_code/core/tool/shell/bash_tool.py +2 -2
- klaude_code/llm/openai_compatible/stream.py +2 -1
- klaude_code/protocol/model.py +24 -1
- klaude_code/session/export.py +1 -1
- klaude_code/session/selector.py +2 -2
- klaude_code/session/session.py +4 -4
- klaude_code/ui/modes/repl/completers.py +4 -4
- klaude_code/ui/modes/repl/event_handler.py +23 -4
- klaude_code/ui/modes/repl/input_prompt_toolkit.py +4 -4
- klaude_code/ui/modes/repl/key_bindings.py +4 -4
- klaude_code/ui/modes/repl/renderer.py +22 -17
- klaude_code/ui/renderers/diffs.py +1 -1
- klaude_code/ui/renderers/metadata.py +2 -2
- klaude_code/ui/renderers/sub_agent.py +14 -12
- klaude_code/ui/renderers/thinking.py +1 -1
- klaude_code/ui/renderers/tools.py +27 -3
- klaude_code/ui/rich/markdown.py +35 -15
- klaude_code/ui/rich/theme.py +2 -5
- klaude_code/ui/terminal/color.py +1 -1
- klaude_code/ui/terminal/control.py +4 -4
- {klaude_code-1.2.25.dist-info → klaude_code-1.2.27.dist-info}/METADATA +121 -127
- {klaude_code-1.2.25.dist-info → klaude_code-1.2.27.dist-info}/RECORD +42 -39
- {klaude_code-1.2.25.dist-info → klaude_code-1.2.27.dist-info}/WHEEL +0 -0
- {klaude_code-1.2.25.dist-info → klaude_code-1.2.27.dist-info}/entry_points.txt +0 -0
|
@@ -18,8 +18,8 @@ from klaude_code.ui.rich.theme import ThemeKey
|
|
|
18
18
|
|
|
19
19
|
# Tool markers (Unicode symbols for UI display)
|
|
20
20
|
MARK_GENERIC = "⚒"
|
|
21
|
-
MARK_BASH = "
|
|
22
|
-
MARK_PLAN = "
|
|
21
|
+
MARK_BASH = "$"
|
|
22
|
+
MARK_PLAN = "Ξ"
|
|
23
23
|
MARK_READ = "←"
|
|
24
24
|
MARK_EDIT = "±"
|
|
25
25
|
MARK_WRITE = "+"
|
|
@@ -528,19 +528,28 @@ def render_tool_call(e: events.ToolCallEvent) -> RenderableType | None:
|
|
|
528
528
|
def _extract_diff(ui_extra: model.ToolResultUIExtra | None) -> model.DiffUIExtra | None:
|
|
529
529
|
if isinstance(ui_extra, model.DiffUIExtra):
|
|
530
530
|
return ui_extra
|
|
531
|
+
if isinstance(ui_extra, model.MultiUIExtra):
|
|
532
|
+
for item in ui_extra.items:
|
|
533
|
+
if isinstance(item, model.DiffUIExtra):
|
|
534
|
+
return item
|
|
531
535
|
return None
|
|
532
536
|
|
|
533
537
|
|
|
534
538
|
def _extract_markdown_doc(ui_extra: model.ToolResultUIExtra | None) -> model.MarkdownDocUIExtra | None:
|
|
535
539
|
if isinstance(ui_extra, model.MarkdownDocUIExtra):
|
|
536
540
|
return ui_extra
|
|
541
|
+
if isinstance(ui_extra, model.MultiUIExtra):
|
|
542
|
+
for item in ui_extra.items:
|
|
543
|
+
if isinstance(item, model.MarkdownDocUIExtra):
|
|
544
|
+
return item
|
|
537
545
|
return None
|
|
538
546
|
|
|
539
547
|
|
|
540
548
|
def render_markdown_doc(md_ui: model.MarkdownDocUIExtra, *, code_theme: str) -> RenderableType:
|
|
541
549
|
"""Render markdown document content in a panel."""
|
|
550
|
+
header = render_path(md_ui.file_path, ThemeKey.TOOL_PARAM_FILE_PATH)
|
|
542
551
|
return Panel.fit(
|
|
543
|
-
NoInsetMarkdown(md_ui.content, code_theme=code_theme),
|
|
552
|
+
Group(header, Text(""), NoInsetMarkdown(md_ui.content, code_theme=code_theme)),
|
|
544
553
|
box=box.SIMPLE,
|
|
545
554
|
border_style=ThemeKey.LINES,
|
|
546
555
|
style=ThemeKey.WRITE_MARKDOWN_PANEL,
|
|
@@ -562,6 +571,19 @@ def render_tool_result(e: events.ToolResultEvent, *, code_theme: str = "monokai"
|
|
|
562
571
|
error_msg = truncate_display(e.result)
|
|
563
572
|
return r_errors.render_error(error_msg)
|
|
564
573
|
|
|
574
|
+
# Render multiple ui blocks if present
|
|
575
|
+
if isinstance(e.ui_extra, model.MultiUIExtra) and e.ui_extra.items:
|
|
576
|
+
rendered: list[RenderableType] = []
|
|
577
|
+
for item in e.ui_extra.items:
|
|
578
|
+
if isinstance(item, model.MarkdownDocUIExtra):
|
|
579
|
+
rendered.append(Padding.indent(render_markdown_doc(item, code_theme=code_theme), level=2))
|
|
580
|
+
elif isinstance(item, model.DiffUIExtra):
|
|
581
|
+
show_file_name = e.tool_name == tools.APPLY_PATCH
|
|
582
|
+
rendered.append(
|
|
583
|
+
Padding.indent(r_diffs.render_structured_diff(item, show_file_name=show_file_name), level=2)
|
|
584
|
+
)
|
|
585
|
+
return Group(*rendered) if rendered else None
|
|
586
|
+
|
|
565
587
|
# Show truncation info if output was truncated and saved to file
|
|
566
588
|
truncation_info = get_truncation_info(e)
|
|
567
589
|
if truncation_info:
|
|
@@ -580,6 +602,8 @@ def render_tool_result(e: events.ToolResultEvent, *, code_theme: str = "monokai"
|
|
|
580
602
|
return Padding.indent(render_markdown_doc(md_ui, code_theme=code_theme), level=2)
|
|
581
603
|
return Padding.indent(r_diffs.render_structured_diff(diff_ui) if diff_ui else Text(""), level=2)
|
|
582
604
|
case tools.APPLY_PATCH:
|
|
605
|
+
if md_ui:
|
|
606
|
+
return Padding.indent(render_markdown_doc(md_ui, code_theme=code_theme), level=2)
|
|
583
607
|
if diff_ui:
|
|
584
608
|
return Padding.indent(r_diffs.render_structured_diff(diff_ui, show_file_name=True), level=2)
|
|
585
609
|
if len(e.result.strip()) == 0:
|
klaude_code/ui/rich/markdown.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# copy from https://github.com/Aider-AI/aider/blob/main/aider/mdstream.py
|
|
2
1
|
from __future__ import annotations
|
|
3
2
|
|
|
4
3
|
import contextlib
|
|
@@ -9,11 +8,13 @@ from typing import Any, ClassVar
|
|
|
9
8
|
|
|
10
9
|
from markdown_it import MarkdownIt
|
|
11
10
|
from markdown_it.token import Token
|
|
11
|
+
from rich import box
|
|
12
12
|
from rich.console import Console, ConsoleOptions, RenderableType, RenderResult
|
|
13
|
-
from rich.markdown import CodeBlock, Heading, Markdown, MarkdownElement
|
|
13
|
+
from rich.markdown import CodeBlock, Heading, Markdown, MarkdownElement, TableElement
|
|
14
14
|
from rich.rule import Rule
|
|
15
15
|
from rich.style import Style, StyleType
|
|
16
16
|
from rich.syntax import Syntax
|
|
17
|
+
from rich.table import Table
|
|
17
18
|
from rich.text import Text
|
|
18
19
|
from rich.theme import Theme
|
|
19
20
|
|
|
@@ -53,6 +54,24 @@ class Divider(MarkdownElement):
|
|
|
53
54
|
yield Rule(style=style, characters="-")
|
|
54
55
|
|
|
55
56
|
|
|
57
|
+
class MinimalHeavyHeadTable(TableElement):
|
|
58
|
+
"""A table element with MINIMAL_HEAVY_HEAD box style."""
|
|
59
|
+
|
|
60
|
+
def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
|
|
61
|
+
table = Table(box=box.MARKDOWN)
|
|
62
|
+
|
|
63
|
+
if self.header is not None and self.header.row is not None:
|
|
64
|
+
for column in self.header.row.cells:
|
|
65
|
+
table.add_column(column.content)
|
|
66
|
+
|
|
67
|
+
if self.body is not None:
|
|
68
|
+
for row in self.body.rows:
|
|
69
|
+
row_content = [element.content for element in row.cells]
|
|
70
|
+
table.add_row(*row_content)
|
|
71
|
+
|
|
72
|
+
yield table
|
|
73
|
+
|
|
74
|
+
|
|
56
75
|
class LeftHeading(Heading):
|
|
57
76
|
"""A heading class that renders left-justified."""
|
|
58
77
|
|
|
@@ -64,7 +83,7 @@ class LeftHeading(Heading):
|
|
|
64
83
|
yield h1_text
|
|
65
84
|
elif self.tag == "h2":
|
|
66
85
|
text.stylize(Style(bold=True, underline=False))
|
|
67
|
-
yield
|
|
86
|
+
yield text
|
|
68
87
|
else:
|
|
69
88
|
yield text
|
|
70
89
|
|
|
@@ -78,6 +97,7 @@ class NoInsetMarkdown(Markdown):
|
|
|
78
97
|
"code_block": NoInsetCodeBlock,
|
|
79
98
|
"heading_open": LeftHeading,
|
|
80
99
|
"hr": Divider,
|
|
100
|
+
"table_open": MinimalHeavyHeadTable,
|
|
81
101
|
}
|
|
82
102
|
|
|
83
103
|
|
|
@@ -90,6 +110,7 @@ class ThinkingMarkdown(Markdown):
|
|
|
90
110
|
"code_block": ThinkingCodeBlock,
|
|
91
111
|
"heading_open": LeftHeading,
|
|
92
112
|
"hr": Divider,
|
|
113
|
+
"table_open": MinimalHeavyHeadTable,
|
|
93
114
|
}
|
|
94
115
|
|
|
95
116
|
|
|
@@ -171,7 +192,7 @@ class MarkdownStream:
|
|
|
171
192
|
|
|
172
193
|
try:
|
|
173
194
|
tokens = self._parser.parse(text)
|
|
174
|
-
except Exception:
|
|
195
|
+
except Exception: # markdown-it-py may raise various internal errors during parsing
|
|
175
196
|
return 0
|
|
176
197
|
|
|
177
198
|
top_level: list[Token] = [token for token in tokens if token.level == 0 and token.map is not None]
|
|
@@ -341,9 +362,6 @@ class MarkdownStream:
|
|
|
341
362
|
def update(self, text: str, final: bool = False) -> None:
|
|
342
363
|
"""Update the display with the latest full markdown buffer."""
|
|
343
364
|
|
|
344
|
-
if self._live_sink is None:
|
|
345
|
-
return
|
|
346
|
-
|
|
347
365
|
now = time.time()
|
|
348
366
|
if not final and now - self.when < self.min_delay:
|
|
349
367
|
return
|
|
@@ -374,18 +392,20 @@ class MarkdownStream:
|
|
|
374
392
|
self._stable_source_line_count = stable_line
|
|
375
393
|
|
|
376
394
|
if final:
|
|
377
|
-
self._live_sink
|
|
395
|
+
if self._live_sink is not None:
|
|
396
|
+
self._live_sink(None)
|
|
378
397
|
return
|
|
379
398
|
|
|
380
|
-
|
|
381
|
-
|
|
399
|
+
if const.MARKDOWN_STREAM_LIVE_REPAINT_ENABLED and self._live_sink is not None:
|
|
400
|
+
apply_mark_live = self._stable_source_line_count == 0
|
|
401
|
+
live_lines = self._render_markdown_to_lines(live_source, apply_mark=apply_mark_live)
|
|
382
402
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
403
|
+
if self._stable_rendered_lines and not self._stable_rendered_lines[-1].strip():
|
|
404
|
+
while live_lines and not live_lines[0].strip():
|
|
405
|
+
live_lines.pop(0)
|
|
386
406
|
|
|
387
|
-
|
|
388
|
-
|
|
407
|
+
live_text = Text.from_ansi("".join(live_lines))
|
|
408
|
+
self._live_sink(live_text)
|
|
389
409
|
|
|
390
410
|
elapsed = time.time() - start
|
|
391
411
|
self.min_delay = min(max(elapsed * 6, 1.0 / 30), 0.5)
|
klaude_code/ui/rich/theme.py
CHANGED
|
@@ -276,7 +276,7 @@ def get_theme(theme: str | None = None) -> Themes:
|
|
|
276
276
|
ThemeKey.RESUME_FLAG.value: "bold reverse " + palette.green,
|
|
277
277
|
ThemeKey.RESUME_INFO.value: palette.green,
|
|
278
278
|
# CONFIGURATION DISPLAY
|
|
279
|
-
ThemeKey.CONFIG_TABLE_HEADER.value: palette.
|
|
279
|
+
ThemeKey.CONFIG_TABLE_HEADER.value: palette.grey1,
|
|
280
280
|
ThemeKey.CONFIG_STATUS_OK.value: palette.green,
|
|
281
281
|
ThemeKey.CONFIG_STATUS_PRIMARY.value: palette.yellow,
|
|
282
282
|
ThemeKey.CONFIG_STATUS_ERROR.value: palette.red,
|
|
@@ -291,7 +291,7 @@ def get_theme(theme: str | None = None) -> Themes:
|
|
|
291
291
|
"markdown.code.border": palette.grey3,
|
|
292
292
|
"markdown.h1": "bold reverse",
|
|
293
293
|
"markdown.h1.border": palette.grey3,
|
|
294
|
-
"markdown.h2
|
|
294
|
+
"markdown.h2": "bold underline",
|
|
295
295
|
"markdown.h3": "bold " + palette.grey1,
|
|
296
296
|
"markdown.h4": "bold " + palette.grey2,
|
|
297
297
|
"markdown.hr": palette.grey3,
|
|
@@ -311,7 +311,6 @@ def get_theme(theme: str | None = None) -> Themes:
|
|
|
311
311
|
"markdown.code.border": palette.grey3,
|
|
312
312
|
"markdown.h1": "bold reverse",
|
|
313
313
|
"markdown.h1.border": palette.grey3,
|
|
314
|
-
"markdown.h2.border": palette.grey3,
|
|
315
314
|
"markdown.h3": "bold " + palette.grey1,
|
|
316
315
|
"markdown.h4": "bold " + palette.grey2,
|
|
317
316
|
"markdown.hr": palette.grey3,
|
|
@@ -329,7 +328,6 @@ def get_theme(theme: str | None = None) -> Themes:
|
|
|
329
328
|
Style(color=palette.blue),
|
|
330
329
|
Style(color=palette.purple),
|
|
331
330
|
Style(color=palette.orange),
|
|
332
|
-
Style(color=palette.red),
|
|
333
331
|
Style(color=palette.grey1),
|
|
334
332
|
Style(color=palette.yellow),
|
|
335
333
|
],
|
|
@@ -339,7 +337,6 @@ def get_theme(theme: str | None = None) -> Themes:
|
|
|
339
337
|
Style(bgcolor=palette.blue_sub_background),
|
|
340
338
|
Style(bgcolor=palette.purple_background),
|
|
341
339
|
Style(bgcolor=palette.orange_background),
|
|
342
|
-
Style(bgcolor=palette.red_background),
|
|
343
340
|
Style(bgcolor=palette.grey_background),
|
|
344
341
|
Style(bgcolor=palette.yellow_background),
|
|
345
342
|
],
|
klaude_code/ui/terminal/color.py
CHANGED
|
@@ -182,7 +182,7 @@ def _parse_osc_color_response(data: bytes) -> tuple[int, int, int] | None:
|
|
|
182
182
|
|
|
183
183
|
try:
|
|
184
184
|
text = data.decode("ascii", errors="ignore")
|
|
185
|
-
except
|
|
185
|
+
except LookupError: # encoding lookup failure (should not happen with "ascii")
|
|
186
186
|
return None
|
|
187
187
|
|
|
188
188
|
match = _OSC_BG_REGEX.search(text)
|
|
@@ -48,7 +48,7 @@ def start_esc_interrupt_monitor(
|
|
|
48
48
|
try:
|
|
49
49
|
fd = sys.stdin.fileno()
|
|
50
50
|
old = termios.tcgetattr(fd)
|
|
51
|
-
except
|
|
51
|
+
except OSError as exc: # pragma: no cover - environment dependent
|
|
52
52
|
log((f"esc monitor init error: {exc}", "r red"))
|
|
53
53
|
return
|
|
54
54
|
|
|
@@ -60,7 +60,7 @@ def start_esc_interrupt_monitor(
|
|
|
60
60
|
continue
|
|
61
61
|
try:
|
|
62
62
|
ch = os.read(fd, 1).decode(errors="ignore")
|
|
63
|
-
except
|
|
63
|
+
except OSError:
|
|
64
64
|
continue
|
|
65
65
|
if ch != "\x1b":
|
|
66
66
|
continue
|
|
@@ -71,7 +71,7 @@ def start_esc_interrupt_monitor(
|
|
|
71
71
|
while r2:
|
|
72
72
|
try:
|
|
73
73
|
seq += os.read(fd, 1).decode(errors="ignore")
|
|
74
|
-
except
|
|
74
|
+
except OSError:
|
|
75
75
|
break
|
|
76
76
|
r2, _, _ = select.select([sys.stdin], [], [], 0.0)
|
|
77
77
|
|
|
@@ -127,7 +127,7 @@ def install_sigint_double_press_exit(
|
|
|
127
127
|
|
|
128
128
|
try:
|
|
129
129
|
signal.signal(signal.SIGINT, _handler)
|
|
130
|
-
except
|
|
130
|
+
except (OSError, ValueError): # pragma: no cover - platform dependent
|
|
131
131
|
# If installing the handler fails, restore() will be a no-op.
|
|
132
132
|
return lambda: None
|
|
133
133
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: klaude-code
|
|
3
|
-
Version: 1.2.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 1.2.27
|
|
4
|
+
Summary: Minimal code agent CLI
|
|
5
5
|
Requires-Dist: anthropic>=0.66.0
|
|
6
6
|
Requires-Dist: chardet>=5.2.0
|
|
7
7
|
Requires-Dist: ddgs>=9.9.3
|
|
@@ -21,7 +21,7 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
|
|
22
22
|
# Klaude Code
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
Minimal code agent CLI.
|
|
25
25
|
|
|
26
26
|
## Features
|
|
27
27
|
- **Multi-provider**: Anthropic, OpenAI Responses API, OpenRouter
|
|
@@ -92,147 +92,141 @@ klaude [--model <name>] [--select-model]
|
|
|
92
92
|
|
|
93
93
|
### Configuration
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
#### Quick Start (Zero Config)
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
Klaude comes with built-in provider configurations. Just set an API key environment variable and start using it:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Pick one (or more) of these:
|
|
101
|
+
export ANTHROPIC_API_KEY=sk-ant-xxx # Claude models
|
|
102
|
+
export OPENAI_API_KEY=sk-xxx # GPT models
|
|
103
|
+
export OPENROUTER_API_KEY=sk-or-xxx # OpenRouter (multi-provider)
|
|
104
|
+
export DEEPSEEK_API_KEY=sk-xxx # DeepSeek models
|
|
105
|
+
export MOONSHOT_API_KEY=sk-xxx # Moonshot/Kimi models
|
|
106
|
+
|
|
107
|
+
# Then just run:
|
|
108
|
+
klaude
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
On first run, you'll be prompted to select a model. Your choice is saved as `main_model`.
|
|
112
|
+
|
|
113
|
+
#### Built-in Providers
|
|
114
|
+
|
|
115
|
+
| Provider | Env Variable | Models |
|
|
116
|
+
|-------------|-----------------------|-------------------------------------------------------------------------------|
|
|
117
|
+
| anthropic | `ANTHROPIC_API_KEY` | sonnet, opus |
|
|
118
|
+
| openai | `OPENAI_API_KEY` | gpt-5.2 |
|
|
119
|
+
| openrouter | `OPENROUTER_API_KEY` | gpt-5.2, gpt-5.2-fast, gpt-5.1-codex-max, sonnet, opus, haiku, kimi, gemini-* |
|
|
120
|
+
| deepseek | `DEEPSEEK_API_KEY` | deepseek |
|
|
121
|
+
| moonshot | `MOONSHOT_API_KEY` | kimi@moonshot |
|
|
122
|
+
| codex | N/A (OAuth) | gpt-5.2-codex |
|
|
123
|
+
|
|
124
|
+
List all configured providers and models:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
klaude list
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Models from providers without a valid API key are shown as dimmed/unavailable.
|
|
131
|
+
|
|
132
|
+
#### Custom Configuration
|
|
133
|
+
|
|
134
|
+
User config file: `~/.klaude/klaude-config.yaml`
|
|
135
|
+
|
|
136
|
+
Open in editor:
|
|
98
137
|
|
|
99
138
|
```bash
|
|
100
139
|
klaude config
|
|
101
140
|
```
|
|
102
141
|
|
|
103
|
-
|
|
142
|
+
##### Adding Models to Built-in Providers
|
|
143
|
+
|
|
144
|
+
You can add custom models to existing providers without redefining the entire provider:
|
|
104
145
|
|
|
105
146
|
```yaml
|
|
147
|
+
# Just specify provider_name and your new models - no need for protocol/api_key
|
|
106
148
|
provider_list:
|
|
107
|
-
- provider_name: openrouter
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
-
|
|
116
|
-
protocol: anthropic
|
|
117
|
-
api_key: <your-anthropic-api-key>
|
|
118
|
-
|
|
119
|
-
- provider_name: moonshot
|
|
120
|
-
protocol: anthropic
|
|
121
|
-
base_url: https://api.moonshot.cn/anthropic
|
|
122
|
-
api_key: <your-api-key>
|
|
123
|
-
|
|
124
|
-
- provider_name: deepseek
|
|
125
|
-
protocol: anthropic
|
|
126
|
-
base_url: https://api.deepseek.com/anthropic
|
|
127
|
-
api_key: <your-api-key>
|
|
128
|
-
|
|
129
|
-
model_list:
|
|
130
|
-
|
|
131
|
-
- model_name: deepseek
|
|
132
|
-
provider: deepseek
|
|
133
|
-
model_params:
|
|
134
|
-
model: deepseek-reasoner
|
|
135
|
-
context_limit: 128000
|
|
136
|
-
thinking:
|
|
137
|
-
type: enabled
|
|
138
|
-
budget_tokens: 8192
|
|
139
|
-
cost:
|
|
140
|
-
currency: CNY
|
|
141
|
-
input: 2
|
|
142
|
-
output: 3
|
|
143
|
-
cache_read: 0.2
|
|
144
|
-
|
|
145
|
-
- model_name: codex-max
|
|
146
|
-
provider: openai-responses
|
|
147
|
-
model_params:
|
|
148
|
-
model: gpt-5.1-codex-max
|
|
149
|
-
thinking:
|
|
150
|
-
reasoning_effort: medium
|
|
151
|
-
context_limit: 400000
|
|
152
|
-
max_tokens: 128000
|
|
153
|
-
cost:
|
|
154
|
-
input: 1.25
|
|
155
|
-
output: 10
|
|
156
|
-
cache_read: 0.13
|
|
157
|
-
|
|
158
|
-
- model_name: gpt-5.1
|
|
159
|
-
provider: openrouter
|
|
160
|
-
model_params:
|
|
161
|
-
model: openai/gpt-5.1
|
|
162
|
-
context_limit: 400000
|
|
163
|
-
max_tokens: 128000
|
|
164
|
-
verbosity: high
|
|
165
|
-
thinking:
|
|
166
|
-
reasoning_effort: high
|
|
167
|
-
cost:
|
|
168
|
-
input: 1.25
|
|
169
|
-
output: 10
|
|
170
|
-
cache_read: 0.13
|
|
171
|
-
|
|
172
|
-
- model_name: kimi@moonshot
|
|
173
|
-
provider: moonshot
|
|
174
|
-
model_params:
|
|
175
|
-
model: kimi-k2-thinking
|
|
176
|
-
context_limit: 262144
|
|
177
|
-
thinking:
|
|
178
|
-
type: enabled
|
|
179
|
-
budget_tokens: 8192
|
|
180
|
-
cost:
|
|
181
|
-
currency: CNY
|
|
182
|
-
input: 4
|
|
183
|
-
output: 16
|
|
184
|
-
cache_read: 1
|
|
185
|
-
|
|
186
|
-
- model_name: opus
|
|
187
|
-
provider: openrouter
|
|
188
|
-
model_params:
|
|
189
|
-
model: anthropic/claude-4.5-opus
|
|
190
|
-
context_limit: 200000
|
|
191
|
-
provider_routing:
|
|
192
|
-
only: [ google-vertex ]
|
|
193
|
-
verbosity: high
|
|
194
|
-
thinking:
|
|
195
|
-
type: enabled
|
|
196
|
-
budget_tokens: 31999
|
|
197
|
-
cost:
|
|
198
|
-
input: 5
|
|
199
|
-
output: 25
|
|
200
|
-
cache_read: 0.5
|
|
201
|
-
cache_write: 6.25
|
|
202
|
-
|
|
203
|
-
- model_name: gemini
|
|
204
|
-
provider: openrouter
|
|
205
|
-
model_params:
|
|
206
|
-
model: google/gemini-3-pro-preview
|
|
207
|
-
context_limit: 1048576
|
|
208
|
-
thinking:
|
|
209
|
-
reasoning_effort: medium
|
|
210
|
-
cost:
|
|
211
|
-
input: 2
|
|
212
|
-
output: 12
|
|
213
|
-
cache_read: 0.2
|
|
214
|
-
|
|
215
|
-
- model_name: haiku
|
|
216
|
-
provider: anthropic
|
|
217
|
-
model_params:
|
|
218
|
-
model: claude-haiku-4-5-20251001
|
|
219
|
-
context_limit: 200000
|
|
220
|
-
cost:
|
|
221
|
-
input: 1
|
|
222
|
-
output: 5
|
|
223
|
-
cache_read: 0.1
|
|
224
|
-
cache_write: 1.25
|
|
149
|
+
- provider_name: openrouter
|
|
150
|
+
model_list:
|
|
151
|
+
- model_name: my-custom-model
|
|
152
|
+
model_params:
|
|
153
|
+
model: some-provider/some-model-id
|
|
154
|
+
context_limit: 200000
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Your models are merged with built-in models. To override a built-in model, use the same `model_name`.
|
|
225
158
|
|
|
159
|
+
##### Overriding Provider Settings
|
|
160
|
+
|
|
161
|
+
Override provider-level settings (like api_key) while keeping built-in models:
|
|
162
|
+
|
|
163
|
+
```yaml
|
|
164
|
+
provider_list:
|
|
165
|
+
- provider_name: anthropic
|
|
166
|
+
api_key: sk-my-custom-key # Override the default ${ANTHROPIC_API_KEY}
|
|
167
|
+
# Built-in models (sonnet, opus) are still available
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
##### Adding New Providers
|
|
171
|
+
|
|
172
|
+
For providers not in the built-in list, you must specify `protocol`:
|
|
173
|
+
|
|
174
|
+
```yaml
|
|
175
|
+
provider_list:
|
|
176
|
+
- provider_name: my-azure-openai
|
|
177
|
+
protocol: openai
|
|
178
|
+
api_key: ${AZURE_OPENAI_KEY}
|
|
179
|
+
base_url: https://my-instance.openai.azure.com/
|
|
180
|
+
is_azure: true
|
|
181
|
+
azure_api_version: "2024-02-15-preview"
|
|
182
|
+
model_list:
|
|
183
|
+
- model_name: gpt-4-azure
|
|
184
|
+
model_params:
|
|
185
|
+
model: gpt-4
|
|
186
|
+
context_limit: 128000
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
##### Full Example
|
|
190
|
+
|
|
191
|
+
```yaml
|
|
192
|
+
# User configuration - merged with built-in config
|
|
226
193
|
main_model: opus
|
|
227
194
|
|
|
228
195
|
sub_agent_models:
|
|
229
|
-
oracle: gpt-
|
|
230
|
-
explore:
|
|
196
|
+
oracle: gpt-4.1
|
|
197
|
+
explore: sonnet
|
|
231
198
|
task: opus
|
|
232
|
-
webagent:
|
|
199
|
+
webagent: sonnet
|
|
233
200
|
|
|
201
|
+
provider_list:
|
|
202
|
+
# Add models to built-in openrouter
|
|
203
|
+
- provider_name: openrouter
|
|
204
|
+
model_list:
|
|
205
|
+
- model_name: qwen-coder
|
|
206
|
+
model_params:
|
|
207
|
+
model: qwen/qwen-2.5-coder-32b-instruct
|
|
208
|
+
context_limit: 131072
|
|
209
|
+
|
|
210
|
+
# Add a completely new provider
|
|
211
|
+
- provider_name: local-ollama
|
|
212
|
+
protocol: openai
|
|
213
|
+
base_url: http://localhost:11434/v1
|
|
214
|
+
api_key: ollama
|
|
215
|
+
model_list:
|
|
216
|
+
- model_name: local-llama
|
|
217
|
+
model_params:
|
|
218
|
+
model: llama3.2
|
|
219
|
+
context_limit: 8192
|
|
234
220
|
```
|
|
235
221
|
|
|
222
|
+
##### Supported Protocols
|
|
223
|
+
|
|
224
|
+
- `anthropic` - Anthropic Claude API
|
|
225
|
+
- `openai` - OpenAI-compatible API
|
|
226
|
+
- `responses` - OpenAI Responses API (for o-series, GPT-5, Codex)
|
|
227
|
+
- `openrouter` - OpenRouter API
|
|
228
|
+
- `codex` - OpenAI Codex CLI (OAuth-based)
|
|
229
|
+
|
|
236
230
|
List configured providers and models:
|
|
237
231
|
|
|
238
232
|
```bash
|