klaude-code 1.2.16__py3-none-any.whl → 1.2.17__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 (30) hide show
  1. klaude_code/cli/runtime.py +12 -2
  2. klaude_code/command/__init__.py +3 -0
  3. klaude_code/command/export_online_cmd.py +149 -0
  4. klaude_code/config/config.py +16 -17
  5. klaude_code/core/manager/sub_agent_manager.py +1 -1
  6. klaude_code/core/prompts/prompt-sub-agent-oracle.md +0 -1
  7. klaude_code/core/prompts/prompt-sub-agent-web.md +48 -0
  8. klaude_code/core/task.py +8 -0
  9. klaude_code/core/tool/__init__.py +2 -0
  10. klaude_code/core/tool/report_back_tool.py +28 -2
  11. klaude_code/core/tool/web/web_search_tool.md +23 -0
  12. klaude_code/core/tool/web/web_search_tool.py +126 -0
  13. klaude_code/protocol/commands.py +1 -0
  14. klaude_code/protocol/events.py +8 -0
  15. klaude_code/protocol/sub_agent/__init__.py +1 -1
  16. klaude_code/protocol/sub_agent/explore.py +1 -1
  17. klaude_code/protocol/sub_agent/web.py +78 -0
  18. klaude_code/protocol/tools.py +1 -0
  19. klaude_code/session/templates/export_session.html +99 -24
  20. klaude_code/ui/modes/repl/event_handler.py +36 -9
  21. klaude_code/ui/modes/repl/renderer.py +3 -3
  22. klaude_code/ui/renderers/sub_agent.py +14 -10
  23. klaude_code/ui/renderers/tools.py +4 -10
  24. klaude_code/ui/rich/status.py +32 -6
  25. {klaude_code-1.2.16.dist-info → klaude_code-1.2.17.dist-info}/METADATA +112 -21
  26. {klaude_code-1.2.16.dist-info → klaude_code-1.2.17.dist-info}/RECORD +28 -25
  27. klaude_code/core/prompts/prompt-sub-agent-webfetch.md +0 -46
  28. klaude_code/protocol/sub_agent/web_fetch.py +0 -74
  29. {klaude_code-1.2.16.dist-info → klaude_code-1.2.17.dist-info}/WHEEL +0 -0
  30. {klaude_code-1.2.16.dist-info → klaude_code-1.2.17.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,78 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from klaude_code.protocol import tools
6
+ from klaude_code.protocol.sub_agent import SubAgentProfile, register_sub_agent
7
+
8
+ WEB_AGENT_DESCRIPTION = """\
9
+ Launch a sub-agent to search the web, fetch pages, and analyze content. Use this for:
10
+ - Accessing up-to-date information beyond your knowledge cutoff (current events, recent releases, latest docs)
11
+ - Researching topics, news, APIs, or technical references
12
+ - Fetching and analyzing specific URLs
13
+ - Gathering comprehensive information from multiple web sources
14
+
15
+ Capabilities:
16
+ - Search the web to find relevant pages (no URL required)
17
+ - Fetch and parse web pages (HTML-to-Markdown conversion)
18
+ - Follow links across multiple pages autonomously
19
+ - Aggregate findings from multiple sources
20
+
21
+ How to use:
22
+ - Write a clear prompt describing what information you need - the agent will search and fetch as needed
23
+ - Optionally provide a `url` if you already know the target page
24
+ - Use `output_format` (JSON Schema) to get structured data back from the agent
25
+ - Account for "Today's date" in <env>. For example, if <env> says "Today's date: 2025-07-01", and the user wants the latest docs, do not use 2024 in the search query. Use 2025.
26
+
27
+ What you receive:
28
+ - The agent returns a text response summarizing its findings
29
+ - With `output_format`, you receive structured JSON matching your schema
30
+ - The response is the agent's analysis, not raw web content\
31
+ """
32
+
33
+ WEB_AGENT_PARAMETERS = {
34
+ "type": "object",
35
+ "properties": {
36
+ "description": {
37
+ "type": "string",
38
+ "description": "A short (3-5 word) description of the task",
39
+ },
40
+ "url": {
41
+ "type": "string",
42
+ "description": "The URL to fetch and analyze. If not provided, the agent will search the web first",
43
+ },
44
+ "prompt": {
45
+ "type": "string",
46
+ "description": "Instructions for searching, analyzing, or extracting content from the web page",
47
+ },
48
+ "output_format": {
49
+ "type": "object",
50
+ "description": "Optional JSON Schema for sub-agent structured output",
51
+ },
52
+ },
53
+ "required": ["description", "prompt"],
54
+ "additionalProperties": False,
55
+ }
56
+
57
+
58
+ def _web_agent_prompt_builder(args: dict[str, Any]) -> str:
59
+ """Build the WebAgent prompt from tool arguments."""
60
+ url = args.get("url", "")
61
+ prompt = args.get("prompt", "")
62
+ if url:
63
+ return f"URL to fetch: {url}\nTask: {prompt}"
64
+ return prompt
65
+
66
+
67
+ register_sub_agent(
68
+ SubAgentProfile(
69
+ name="WebAgent",
70
+ description=WEB_AGENT_DESCRIPTION,
71
+ parameters=WEB_AGENT_PARAMETERS,
72
+ prompt_file="prompts/prompt-sub-agent-web.md",
73
+ tool_set=(tools.BASH, tools.READ, tools.WEB_FETCH, tools.WEB_SEARCH),
74
+ prompt_builder=_web_agent_prompt_builder,
75
+ active_form="Surfing",
76
+ output_schema_arg="output_format",
77
+ )
78
+ )
@@ -10,6 +10,7 @@ SKILL = "Skill"
10
10
  MERMAID = "Mermaid"
11
11
  MEMORY = "Memory"
12
12
  WEB_FETCH = "WebFetch"
13
+ WEB_SEARCH = "WebSearch"
13
14
  REPORT_BACK = "report_back"
14
15
 
15
16
  # SubAgentType is just a string alias now; agent types are defined via SubAgentProfile
@@ -672,8 +672,102 @@
672
672
  /* Markdown Elements */
673
673
  .markdown-body {
674
674
  font-family: var(--font-markdown);
675
- line-height: 1.5;
675
+ line-height: 1.6;
676
+ font-size: var(--font-size-base);
677
+ }
678
+ .markdown-body > *:first-child {
679
+ margin-top: 0 !important;
680
+ }
681
+ .markdown-body > *:last-child {
682
+ margin-bottom: 0 !important;
683
+ }
684
+
685
+ .markdown-body h1,
686
+ .markdown-body h2,
687
+ .markdown-body h3,
688
+ .markdown-body h4,
689
+ .markdown-body h5,
690
+ .markdown-body h6 {
691
+ margin-top: 24px;
692
+ margin-bottom: 16px;
693
+ font-weight: var(--font-weight-bold);
694
+ line-height: 1.25;
695
+ }
696
+
697
+ .markdown-body a {
698
+ color: var(--accent);
699
+ text-decoration: none;
700
+ border-bottom: 1px solid rgba(8, 81, 178, 0.2);
701
+ transition: border-color 0.2s, background-color 0.2s;
702
+ }
703
+ .markdown-body a:hover {
704
+ border-bottom-color: var(--accent);
705
+ background-color: rgba(8, 81, 178, 0.05);
706
+ border-radius: 2px;
707
+ }
708
+
709
+ .markdown-body p {
710
+ margin-bottom: 8px; /* Tighter spacing */
711
+ }
712
+
713
+ .markdown-body ul,
714
+ .markdown-body ol {
715
+ margin-bottom: 8px; /* Tighter spacing */
716
+ padding-left: 1.5rem;
717
+ list-style-position: outside;
718
+ }
719
+
720
+ .markdown-body ul ul,
721
+ .markdown-body ol ul,
722
+ .markdown-body ul ol,
723
+ .markdown-body ol ol {
724
+ margin-top: 0;
725
+ margin-bottom: 0;
726
+ }
727
+
728
+ .markdown-body li > p {
729
+ margin-bottom: 0;
730
+ }
731
+ .markdown-body li + li {
732
+ margin-top: 0.25em;
676
733
  }
734
+
735
+ .markdown-body blockquote {
736
+ margin: 0 0 16px;
737
+ padding: 0 1em;
738
+ color: var(--text-dim);
739
+ border-left: 0.25em solid var(--border);
740
+ }
741
+
742
+ .markdown-body table {
743
+ border-collapse: collapse;
744
+ width: 100%;
745
+ margin-top: 8px;
746
+ margin-bottom: 16px;
747
+ display: block;
748
+ overflow-x: auto;
749
+ }
750
+
751
+ .markdown-body table tr {
752
+ background-color: var(--bg-card);
753
+ border-top: 1px solid var(--border);
754
+ }
755
+
756
+ .markdown-body table tr:nth-child(2n) {
757
+ background-color: rgba(0, 0, 0, 0.02);
758
+ }
759
+
760
+ .markdown-body table th,
761
+ .markdown-body table td {
762
+ padding: 6px 13px;
763
+ border: 1px solid var(--border);
764
+ }
765
+
766
+ .markdown-body table th {
767
+ font-weight: var(--font-weight-bold);
768
+ background-color: rgba(0, 0, 0, 0.04);
769
+ }
770
+
677
771
  .markdown-body hr {
678
772
  height: 0;
679
773
  margin: 24px 0;
@@ -682,10 +776,10 @@
682
776
  }
683
777
  .markdown-body pre {
684
778
  background: var(--bg-code);
685
- padding: 16px;
779
+ padding: 12px;
686
780
  border-radius: var(--radius-md);
687
781
  overflow-x: auto;
688
- margin: 12px 0;
782
+ margin: 8px 0 16px 0;
689
783
  border: 1px solid var(--border);
690
784
  }
691
785
  .markdown-body code {
@@ -694,36 +788,17 @@
694
788
  font-size: var(--font-size-sm);
695
789
  padding: 2px 4px;
696
790
  border-radius: var(--radius-sm);
791
+ background-color: rgba(0, 0, 0, 0.05); /* Slight bg for inline code */
697
792
  }
698
793
  .markdown-body pre code {
699
794
  background: transparent;
700
795
  padding: 0;
701
796
  border-radius: 0;
797
+ color: inherit;
702
798
  }
703
799
  .markdown-body pre code.hljs {
704
800
  background: transparent;
705
801
  }
706
- .markdown-body p {
707
- margin-bottom: 12px;
708
- }
709
- .markdown-body > *:first-child {
710
- margin-top: 0;
711
- }
712
- .markdown-body > *:last-child {
713
- margin-bottom: 0;
714
- }
715
- .markdown-body ul,
716
- .markdown-body ol {
717
- margin-bottom: 12px;
718
- padding-left: 1.5rem;
719
- list-style-position: outside;
720
- }
721
- .markdown-body ul ul,
722
- .markdown-body ol ul,
723
- .markdown-body ul ol,
724
- .markdown-body ol ol {
725
- margin-left: 1rem;
726
- }
727
802
 
728
803
  /* Diff View */
729
804
  .diff-view {
@@ -137,11 +137,13 @@ class SpinnerStatusState:
137
137
  Composed of two independent layers:
138
138
  - base_status: Set by TodoChange, persistent within a turn
139
139
  - activity: Current activity (composing or tool_calls), mutually exclusive
140
+ - context_percent: Context usage percentage, updated during task execution
140
141
 
141
142
  Display logic:
142
143
  - If activity: show base + activity (if base exists) or activity + "..."
143
144
  - Elif base_status: show base_status
144
145
  - Else: show "Thinking …"
146
+ - Context percent is appended at the end if available
145
147
  """
146
148
 
147
149
  DEFAULT_STATUS = "Thinking …"
@@ -149,11 +151,13 @@ class SpinnerStatusState:
149
151
  def __init__(self) -> None:
150
152
  self._base_status: str | None = None
151
153
  self._activity = ActivityState()
154
+ self._context_percent: float | None = None
152
155
 
153
156
  def reset(self) -> None:
154
157
  """Reset all layers."""
155
158
  self._base_status = None
156
159
  self._activity.reset()
160
+ self._context_percent = None
157
161
 
158
162
  def set_base_status(self, status: str | None) -> None:
159
163
  """Set base status from TodoChange."""
@@ -175,12 +179,16 @@ class SpinnerStatusState:
175
179
  """Clear activity state for a new turn."""
176
180
  self._activity.reset()
177
181
 
182
+ def set_context_percent(self, percent: float) -> None:
183
+ """Set context usage percentage."""
184
+ self._context_percent = percent
185
+
178
186
  def get_activity_text(self) -> Text | None:
179
187
  """Get current activity text. Returns None if idle."""
180
188
  return self._activity.get_activity_text()
181
189
 
182
190
  def get_status(self) -> Text:
183
- """Get current spinner status as rich Text."""
191
+ """Get current spinner status as rich Text (without context)."""
184
192
  activity_text = self._activity.get_activity_text()
185
193
 
186
194
  if self._base_status:
@@ -188,11 +196,19 @@ class SpinnerStatusState:
188
196
  if activity_text:
189
197
  result.append(" | ")
190
198
  result.append_text(activity_text)
191
- return result
192
- if activity_text:
199
+ elif activity_text:
193
200
  activity_text.append(" …")
194
- return activity_text
195
- return Text(self.DEFAULT_STATUS)
201
+ result = activity_text
202
+ else:
203
+ result = Text(self.DEFAULT_STATUS)
204
+
205
+ return result
206
+
207
+ def get_context_text(self) -> Text | None:
208
+ """Get context usage text for right-aligned display."""
209
+ if self._context_percent is None:
210
+ return None
211
+ return Text(f"{self._context_percent:.1f}%", style=ThemeKey.METADATA_DIM)
196
212
 
197
213
 
198
214
  class DisplayEventHandler:
@@ -247,6 +263,8 @@ class DisplayEventHandler:
247
263
  self._on_task_metadata(e)
248
264
  case events.TodoChangeEvent() as e:
249
265
  self._on_todo_change(e)
266
+ case events.ContextUsageEvent() as e:
267
+ self._on_context_usage(e)
250
268
  case events.TurnEndEvent():
251
269
  pass
252
270
  case events.ResponseMetadataEvent():
@@ -412,6 +430,12 @@ class DisplayEventHandler:
412
430
  self.spinner_status.clear_for_new_turn()
413
431
  self._update_spinner()
414
432
 
433
+ def _on_context_usage(self, event: events.ContextUsageEvent) -> None:
434
+ if self.renderer.is_sub_agent_session(event.session_id):
435
+ return
436
+ self.spinner_status.set_context_percent(event.context_percent)
437
+ self._update_spinner()
438
+
415
439
  async def _on_task_finish(self, event: events.TaskFinishEvent) -> None:
416
440
  self.renderer.display_task_finish(event)
417
441
  if not self.renderer.is_sub_agent_session(event.session_id):
@@ -459,7 +483,10 @@ class DisplayEventHandler:
459
483
 
460
484
  def _update_spinner(self) -> None:
461
485
  """Update spinner text from current status state."""
462
- self.renderer.spinner_update(self.spinner_status.get_status())
486
+ self.renderer.spinner_update(
487
+ self.spinner_status.get_status(),
488
+ self.spinner_status.get_context_text(),
489
+ )
463
490
 
464
491
  async def _flush_assistant_buffer(self, state: StreamState) -> None:
465
492
  if state.is_active:
@@ -525,15 +552,15 @@ class DisplayEventHandler:
525
552
  """Calculate max length for base_status based on terminal width.
526
553
 
527
554
  Reserve space for:
528
- - Spinner glyph + space: 2 chars
555
+ - Spinner glyph + space + context text: 2 chars + context text length 10 chars
529
556
  - " | " separator: 3 chars (only if activity text present)
530
557
  - Activity text: actual length (only if present)
531
558
  - Status hint text (esc to interrupt)
532
559
  """
533
560
  terminal_width = self.renderer.console.size.width
534
561
 
535
- # Base reserved space: spinner + status hint
536
- reserved_space = 2 + len(const.STATUS_HINT_TEXT)
562
+ # Base reserved space: spinner + context + status hint
563
+ reserved_space = 12 + len(const.STATUS_HINT_TEXT)
537
564
 
538
565
  # Add space for activity text if present
539
566
  activity_text = self.spinner_status.get_activity_text()
@@ -264,9 +264,9 @@ class REPLRenderer:
264
264
  """Stop the spinner animation."""
265
265
  self._spinner.stop()
266
266
 
267
- def spinner_update(self, status_text: str | Text) -> None:
268
- """Update the spinner status text."""
269
- self._spinner.update(ShimmerStatusText(status_text, ThemeKey.SPINNER_STATUS_TEXT))
267
+ def spinner_update(self, status_text: str | Text, right_text: Text | None = None) -> None:
268
+ """Update the spinner status text with optional right-aligned text."""
269
+ self._spinner.update(ShimmerStatusText(status_text, ThemeKey.SPINNER_STATUS_TEXT, right_text))
270
270
 
271
271
  def spinner_renderable(self) -> Spinner:
272
272
  """Return the spinner's renderable for embedding in other components."""
@@ -16,7 +16,7 @@ from klaude_code.ui.rich.theme import ThemeKey
16
16
 
17
17
  def _compact_schema_value(value: dict[str, Any]) -> str | list[Any] | dict[str, Any]:
18
18
  """Convert a JSON Schema value to compact representation."""
19
- value_type = value.get("type", "any")
19
+ value_type = value.get("type", "any").lower()
20
20
  desc = value.get("description", "")
21
21
 
22
22
  if value_type == "object":
@@ -64,16 +64,20 @@ def render_sub_agent_result(
64
64
 
65
65
  # Use rich JSON for structured output
66
66
  if has_structured_output:
67
- return Panel.fit(
68
- Group(
69
- Text(
70
- "use /export to view full output",
71
- style=ThemeKey.TOOL_RESULT,
67
+ try:
68
+ return Panel.fit(
69
+ Group(
70
+ Text(
71
+ "use /export to view full output",
72
+ style=ThemeKey.TOOL_RESULT,
73
+ ),
74
+ JSON(stripped_result),
72
75
  ),
73
- JSON(stripped_result),
74
- ),
75
- border_style=ThemeKey.LINES,
76
- )
76
+ border_style=ThemeKey.LINES,
77
+ )
78
+ except json.JSONDecodeError:
79
+ # Fall back to markdown if not valid JSON
80
+ pass
77
81
 
78
82
  lines = stripped_result.splitlines()
79
83
  if len(lines) > const.SUB_AGENT_RESULT_MAX_LINES:
@@ -186,14 +186,7 @@ def render_write_tool_call(arguments: str) -> RenderableType:
186
186
  try:
187
187
  json_dict = json.loads(arguments)
188
188
  file_path = json_dict.get("file_path")
189
- op_label = "Create"
190
- if isinstance(file_path, str):
191
- abs_path = Path(file_path)
192
- if not abs_path.is_absolute():
193
- abs_path = (Path().cwd() / abs_path).resolve()
194
- if abs_path.exists():
195
- op_label = "Overwrite"
196
- tool_name_column = Text.assemble(("→", ThemeKey.TOOL_MARK), " ", (op_label, ThemeKey.TOOL_NAME))
189
+ tool_name_column = Text.assemble(("", ThemeKey.TOOL_MARK), " ", ("Write", ThemeKey.TOOL_NAME))
197
190
  arguments_column = render_path(file_path, ThemeKey.TOOL_PARAM_FILE_PATH)
198
191
  except json.JSONDecodeError:
199
192
  tool_name_column = Text.assemble(("→", ThemeKey.TOOL_MARK), " ", ("Write", ThemeKey.TOOL_NAME))
@@ -455,8 +448,9 @@ _TOOL_ACTIVE_FORM: dict[str, str] = {
455
448
  tools.SKILL: "Skilling",
456
449
  tools.MERMAID: "Diagramming",
457
450
  tools.MEMORY: "Memorizing",
458
- tools.WEB_FETCH: "Fetching",
459
- tools.REPORT_BACK: "Submitting Report",
451
+ tools.WEB_FETCH: "Fetching Web",
452
+ tools.WEB_SEARCH: "Searching Web",
453
+ tools.REPORT_BACK: "Reporting",
460
454
  }
461
455
 
462
456
 
@@ -21,15 +21,22 @@ from klaude_code.ui.terminal.color import get_last_terminal_background_rgb
21
21
  BREATHING_SPINNER_NAME = "dots"
22
22
 
23
23
  # Alternating glyphs for the breathing spinner - switches at each "transparent" point
24
- # All glyphs are center-symmetric (point-symmetric)
25
24
  _BREATHING_SPINNER_GLYPHS_BASE = [
26
- # Stars
27
25
  "✦",
28
26
  "✶",
29
27
  "✲",
30
- "⏺",
31
28
  "◆",
32
29
  "❖",
30
+ "✧",
31
+ "❋",
32
+ "✸",
33
+ "✻",
34
+ "◇",
35
+ "✴",
36
+ "✷",
37
+ "⟡",
38
+ "⬡",
39
+ "⬢",
33
40
  ]
34
41
 
35
42
  # Shuffle glyphs on module load for variety across sessions
@@ -172,15 +179,34 @@ def _breathing_style(console: Console, base_style: Style, intensity: float) -> S
172
179
 
173
180
 
174
181
  class ShimmerStatusText:
175
- """Renderable status line with shimmer effect on the main text and hint."""
182
+ """Renderable status line with shimmer effect on the main text and hint.
176
183
 
177
- def __init__(self, main_text: str | Text, main_style: ThemeKey) -> None:
184
+ Supports optional right-aligned text that stays fixed at the right edge.
185
+ """
186
+
187
+ def __init__(self, main_text: str | Text, main_style: ThemeKey, right_text: Text | None = None) -> None:
178
188
  self._main_text = main_text if isinstance(main_text, Text) else Text(main_text)
179
189
  self._main_style = main_style
180
190
  self._hint_text = Text(const.STATUS_HINT_TEXT)
181
191
  self._hint_style = ThemeKey.STATUS_HINT
192
+ self._right_text = right_text
182
193
 
183
194
  def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
195
+ left_text = self._render_left_text(console)
196
+
197
+ if self._right_text is None:
198
+ yield left_text
199
+ return
200
+
201
+ # Use Table.grid to create left-right aligned layout
202
+ table = Table.grid(expand=True)
203
+ table.add_column(justify="left", ratio=1)
204
+ table.add_column(justify="right")
205
+ table.add_row(left_text, self._right_text)
206
+ yield table
207
+
208
+ def _render_left_text(self, console: Console) -> Text:
209
+ """Render the left part with shimmer effect."""
184
210
  result = Text()
185
211
  main_style = console.get_style(str(self._main_style))
186
212
  hint_style = console.get_style(str(self._hint_style))
@@ -198,7 +224,7 @@ class ShimmerStatusText:
198
224
  style = _shimmer_style(console, base_style, intensity)
199
225
  result.append(ch, style=style)
200
226
 
201
- yield result
227
+ return result
202
228
 
203
229
 
204
230
  def spinner_name() -> str:
@@ -1,8 +1,9 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 1.2.16
3
+ Version: 1.2.17
4
4
  Summary: Add your description here
5
5
  Requires-Dist: anthropic>=0.66.0
6
+ Requires-Dist: ddgs>=9.9.3
6
7
  Requires-Dist: openai>=1.102.0
7
8
  Requires-Dist: pillow>=12.0.0
8
9
  Requires-Dist: prompt-toolkit>=3.0.52
@@ -71,47 +72,137 @@ Open the configuration file in editor:
71
72
  klaude config
72
73
  ```
73
74
 
74
- An minimal example config yaml using OpenRouter's API Key:
75
+ An example config yaml:
75
76
 
76
77
  ```yaml
77
78
  provider_list:
78
- - provider_name: openrouter-work
79
+ - provider_name: openrouter
79
80
  protocol: openrouter # support <responses|openrouter|anthropic|openai>
80
81
  api_key: <your-openrouter-api-key>
82
+
83
+ - provider_name: openai-responses
84
+ protocol: responses
85
+ api_key: <your-openai-api-key>
86
+
87
+ - provider_name: anthropic
88
+ protocol: anthropic
89
+ api_key: <your-anthropic-api-key>
90
+
91
+ - provider_name: moonshot
92
+ protocol: anthropic
93
+ base_url: https://api.moonshot.cn/anthropic
94
+ api_key: <your-api-key>
95
+
96
+ - provider_name: deepseek
97
+ protocol: anthropic
98
+ base_url: https://api.deepseek.com/anthropic
99
+ api_key: <your-api-key>
100
+
81
101
  model_list:
82
- - model_name: gpt-5.1-codex
83
- provider: openrouter
102
+
103
+ - model_name: deepseek
104
+ provider: deepseek
105
+ model_params:
106
+ model: deepseek-reasoner
107
+ context_limit: 128000
108
+ thinking:
109
+ type: enabled
110
+ budget_tokens: 8192
111
+ cost:
112
+ currency: CNY
113
+ input: 2
114
+ output: 3
115
+ cache_read: 0.2
116
+
117
+ - model_name: codex-max
118
+ provider: openai-responses
84
119
  model_params:
85
- model: openai/gpt-5.1-codex
86
- context_limit: 368000
120
+ model: gpt-5.1-codex-max
87
121
  thinking:
88
122
  reasoning_effort: medium
89
- - model_name: gpt-5.1-high
123
+ context_limit: 400000
124
+ max_tokens: 128000
125
+ cost:
126
+ input: 1.25
127
+ output: 10
128
+ cache_read: 0.13
129
+
130
+ - model_name: gpt-5.1
90
131
  provider: openrouter
91
132
  model_params:
92
133
  model: openai/gpt-5.1
93
- context_limit: 368000
134
+ context_limit: 400000
135
+ max_tokens: 128000
136
+ verbosity: high
94
137
  thinking:
95
138
  reasoning_effort: high
96
- - model_name: sonnet
139
+ cost:
140
+ input: 1.25
141
+ output: 10
142
+ cache_read: 0.13
143
+
144
+ - model_name: kimi@moonshot
145
+ provider: moonshot
146
+ model_params:
147
+ model: kimi-k2-thinking
148
+ context_limit: 262144
149
+ thinking:
150
+ type: enabled
151
+ budget_tokens: 8192
152
+ cost:
153
+ currency: CNY
154
+ input: 4
155
+ output: 16
156
+ cache_read: 1
157
+
158
+ - model_name: opus
97
159
  provider: openrouter
98
160
  model_params:
99
- model: anthropic/claude-4.5-sonnet
100
- context_limit: 168000
161
+ model: anthropic/claude-4.5-opus
162
+ context_limit: 200000
101
163
  provider_routing:
102
- sort: throughput
103
- - model_name: haiku
164
+ only: [ google-vertex ]
165
+ verbosity: high
166
+ thinking:
167
+ type: enabled
168
+ budget_tokens: 31999
169
+ cost:
170
+ input: 5
171
+ output: 25
172
+ cache_read: 0.5
173
+ cache_write: 6.25
174
+
175
+ - model_name: gemini
104
176
  provider: openrouter
105
177
  model_params:
106
- model: anthropic/claude-haiku-4.5
107
- context_limit: 168000
108
- provider_routing:
109
- sort: throughput
110
- main_model: gpt-5.1-codex
178
+ model: google/gemini-3-pro-preview
179
+ context_limit: 1048576
180
+ thinking:
181
+ reasoning_effort: medium
182
+ cost:
183
+ input: 2
184
+ output: 12
185
+ cache_read: 0.2
186
+
187
+ - model_name: haiku
188
+ provider: anthropic
189
+ model_params:
190
+ model: claude-haiku-4-5-20251001
191
+ context_limit: 200000
192
+ cost:
193
+ input: 1
194
+ output: 5
195
+ cache_read: 0.1
196
+ cache_write: 1.25
197
+
198
+ main_model: opus
199
+
111
200
  sub_agent_models:
112
- oracle: gpt-5.1-high
201
+ oracle: gpt-5.1
113
202
  explore: haiku
114
- task: sonnet
203
+ task: opus
204
+ webfetchagent: haiku
205
+
115
206
  ```
116
207
 
117
208
  List configured providers and models: