klaude-code 2.5.2__py3-none-any.whl → 2.6.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 (61) hide show
  1. klaude_code/auth/__init__.py +10 -0
  2. klaude_code/auth/env.py +77 -0
  3. klaude_code/cli/auth_cmd.py +89 -21
  4. klaude_code/cli/config_cmd.py +5 -5
  5. klaude_code/cli/cost_cmd.py +167 -68
  6. klaude_code/cli/main.py +51 -27
  7. klaude_code/cli/self_update.py +7 -7
  8. klaude_code/config/assets/builtin_config.yaml +45 -24
  9. klaude_code/config/builtin_config.py +23 -9
  10. klaude_code/config/config.py +19 -9
  11. klaude_code/config/model_matcher.py +1 -1
  12. klaude_code/const.py +2 -1
  13. klaude_code/core/tool/file/edit_tool.py +1 -1
  14. klaude_code/core/tool/file/read_tool.py +2 -2
  15. klaude_code/core/tool/file/write_tool.py +1 -1
  16. klaude_code/core/turn.py +21 -4
  17. klaude_code/llm/anthropic/client.py +75 -50
  18. klaude_code/llm/anthropic/input.py +20 -9
  19. klaude_code/llm/google/client.py +235 -148
  20. klaude_code/llm/google/input.py +44 -36
  21. klaude_code/llm/openai_compatible/stream.py +114 -100
  22. klaude_code/llm/openrouter/client.py +1 -0
  23. klaude_code/llm/openrouter/reasoning.py +4 -29
  24. klaude_code/llm/partial_message.py +2 -32
  25. klaude_code/llm/responses/client.py +99 -81
  26. klaude_code/llm/responses/input.py +11 -25
  27. klaude_code/llm/stream_parts.py +94 -0
  28. klaude_code/log.py +57 -0
  29. klaude_code/protocol/events.py +214 -0
  30. klaude_code/protocol/sub_agent/image_gen.py +0 -4
  31. klaude_code/session/session.py +51 -18
  32. klaude_code/tui/command/fork_session_cmd.py +14 -23
  33. klaude_code/tui/command/model_picker.py +2 -17
  34. klaude_code/tui/command/resume_cmd.py +2 -18
  35. klaude_code/tui/command/sub_agent_model_cmd.py +5 -19
  36. klaude_code/tui/command/thinking_cmd.py +2 -14
  37. klaude_code/tui/commands.py +0 -5
  38. klaude_code/tui/components/common.py +1 -1
  39. klaude_code/tui/components/metadata.py +21 -21
  40. klaude_code/tui/components/rich/quote.py +36 -8
  41. klaude_code/tui/components/rich/theme.py +2 -0
  42. klaude_code/tui/components/sub_agent.py +6 -0
  43. klaude_code/tui/display.py +11 -1
  44. klaude_code/tui/input/completers.py +11 -7
  45. klaude_code/tui/input/prompt_toolkit.py +3 -1
  46. klaude_code/tui/machine.py +108 -56
  47. klaude_code/tui/renderer.py +4 -65
  48. klaude_code/tui/terminal/selector.py +174 -31
  49. {klaude_code-2.5.2.dist-info → klaude_code-2.6.0.dist-info}/METADATA +23 -31
  50. {klaude_code-2.5.2.dist-info → klaude_code-2.6.0.dist-info}/RECORD +52 -58
  51. klaude_code/cli/session_cmd.py +0 -96
  52. klaude_code/protocol/events/__init__.py +0 -63
  53. klaude_code/protocol/events/base.py +0 -18
  54. klaude_code/protocol/events/chat.py +0 -30
  55. klaude_code/protocol/events/lifecycle.py +0 -23
  56. klaude_code/protocol/events/metadata.py +0 -16
  57. klaude_code/protocol/events/streaming.py +0 -43
  58. klaude_code/protocol/events/system.py +0 -56
  59. klaude_code/protocol/events/tools.py +0 -27
  60. {klaude_code-2.5.2.dist-info → klaude_code-2.6.0.dist-info}/WHEEL +0 -0
  61. {klaude_code-2.5.2.dist-info → klaude_code-2.6.0.dist-info}/entry_points.txt +0 -0
@@ -1,96 +0,0 @@
1
- import time
2
-
3
- import typer
4
-
5
- from klaude_code.log import log
6
- from klaude_code.session import Session
7
-
8
-
9
- def _session_confirm(sessions: list[Session.SessionMetaBrief], message: str) -> bool:
10
- """Show session list and confirm deletion using prompt_toolkit."""
11
-
12
- from prompt_toolkit.styles import Style
13
-
14
- from klaude_code.tui.terminal.selector import SelectItem, select_one
15
-
16
- def _fmt(ts: float) -> str:
17
- try:
18
- return time.strftime("%m-%d %H:%M:%S", time.localtime(ts))
19
- except (OSError, OverflowError, ValueError):
20
- return str(ts)
21
-
22
- log(f"Sessions to delete ({len(sessions)}):")
23
- for s in sessions:
24
- msg_count_display = "N/A" if s.messages_count == -1 else str(s.messages_count)
25
- first_msg_text = s.user_messages[0] if s.user_messages else ""
26
- first_msg = first_msg_text.strip().replace("\n", " ")[:50]
27
- if len(first_msg_text) > 50:
28
- first_msg += "…"
29
- log(f" {_fmt(s.updated_at)} {msg_count_display:>3} msgs {first_msg}")
30
-
31
- items: list[SelectItem[bool]] = [
32
- SelectItem(title=[("class:text", "No\n")], value=False, search_text="No"),
33
- SelectItem(title=[("class:text", "Yes\n")], value=True, search_text="Yes"),
34
- ]
35
-
36
- result = select_one(
37
- message=message,
38
- items=items,
39
- pointer="→",
40
- style=Style(
41
- [
42
- ("question", "bold"),
43
- ("pointer", "ansigreen"),
44
- ("highlighted", "ansigreen"),
45
- ("text", ""),
46
- ]
47
- ),
48
- use_search_filter=False,
49
- )
50
- return bool(result)
51
-
52
-
53
- def session_clean(
54
- min_messages: int = typer.Option(5, "--min", "-n", help="Minimum messages to keep a session"),
55
- yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt"),
56
- ) -> None:
57
- """Remove sessions with fewer than N messages (default: 5)"""
58
- sessions = Session.list_sessions()
59
- to_delete = [s for s in sessions if 0 <= s.messages_count < min_messages]
60
-
61
- if not to_delete:
62
- log(f"No sessions with fewer than {min_messages} messages found.")
63
- return
64
-
65
- if not yes and not _session_confirm(to_delete, "Delete these sessions?"):
66
- log("Aborted.")
67
- return
68
-
69
- deleted = Session.clean_small_sessions(min_messages)
70
- log(f"Deleted {deleted} session(s).")
71
-
72
-
73
- def session_clean_all(
74
- yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt"),
75
- ) -> None:
76
- """Remove all sessions for the current project"""
77
- sessions = Session.list_sessions()
78
-
79
- if not sessions:
80
- log("No sessions found.")
81
- return
82
-
83
- if not yes and not _session_confirm(sessions, "Delete ALL sessions? This cannot be undone."):
84
- log("Aborted.")
85
- return
86
-
87
- deleted = Session.clean_all_sessions()
88
- log(f"Deleted {deleted} session(s).")
89
-
90
-
91
- def register_session_commands(app: typer.Typer) -> None:
92
- """Register session subcommands to the given Typer app."""
93
- session_app = typer.Typer(help="Manage sessions for the current project")
94
- session_app.command("clean")(session_clean)
95
- session_app.command("clean-all")(session_clean_all)
96
- app.add_typer(session_app, name="session")
@@ -1,63 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from klaude_code.protocol.events.base import Event, ResponseEvent
4
- from klaude_code.protocol.events.chat import (
5
- CommandOutputEvent,
6
- DeveloperMessageEvent,
7
- TodoChangeEvent,
8
- UserMessageEvent,
9
- )
10
- from klaude_code.protocol.events.lifecycle import TaskFinishEvent, TaskStartEvent, TurnEndEvent, TurnStartEvent
11
- from klaude_code.protocol.events.metadata import TaskMetadataEvent, UsageEvent
12
- from klaude_code.protocol.events.streaming import (
13
- AssistantImageDeltaEvent,
14
- AssistantTextDeltaEvent,
15
- AssistantTextEndEvent,
16
- AssistantTextStartEvent,
17
- ResponseCompleteEvent,
18
- ThinkingDeltaEvent,
19
- ThinkingEndEvent,
20
- ThinkingStartEvent,
21
- ToolCallStartEvent,
22
- )
23
- from klaude_code.protocol.events.system import (
24
- EndEvent,
25
- ErrorEvent,
26
- InterruptEvent,
27
- ReplayEventUnion,
28
- ReplayHistoryEvent,
29
- WelcomeEvent,
30
- )
31
- from klaude_code.protocol.events.tools import ToolCallEvent, ToolResultEvent
32
-
33
- __all__ = [
34
- "AssistantImageDeltaEvent",
35
- "AssistantTextDeltaEvent",
36
- "AssistantTextEndEvent",
37
- "AssistantTextStartEvent",
38
- "CommandOutputEvent",
39
- "DeveloperMessageEvent",
40
- "EndEvent",
41
- "ErrorEvent",
42
- "Event",
43
- "InterruptEvent",
44
- "ReplayEventUnion",
45
- "ReplayHistoryEvent",
46
- "ResponseCompleteEvent",
47
- "ResponseEvent",
48
- "TaskFinishEvent",
49
- "TaskMetadataEvent",
50
- "TaskStartEvent",
51
- "ThinkingDeltaEvent",
52
- "ThinkingEndEvent",
53
- "ThinkingStartEvent",
54
- "TodoChangeEvent",
55
- "ToolCallEvent",
56
- "ToolCallStartEvent",
57
- "ToolResultEvent",
58
- "TurnEndEvent",
59
- "TurnStartEvent",
60
- "UsageEvent",
61
- "UserMessageEvent",
62
- "WelcomeEvent",
63
- ]
@@ -1,18 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import time
4
-
5
- from pydantic import BaseModel, Field
6
-
7
-
8
- class Event(BaseModel):
9
- """Base event."""
10
-
11
- session_id: str
12
- timestamp: float = Field(default_factory=time.time)
13
-
14
-
15
- class ResponseEvent(Event):
16
- """Event associated with a single model response."""
17
-
18
- response_id: str | None = None
@@ -1,30 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from klaude_code.protocol import message, model
4
- from klaude_code.protocol.commands import CommandName
5
-
6
- from .base import Event
7
-
8
-
9
- class UserMessageEvent(Event):
10
- content: str
11
- images: list[message.ImageURLPart] | None = None
12
-
13
-
14
- class DeveloperMessageEvent(Event):
15
- """DeveloperMessages are reminders in user messages or tool results."""
16
-
17
- item: message.DeveloperMessage
18
-
19
-
20
- class TodoChangeEvent(Event):
21
- todos: list[model.TodoItem]
22
-
23
-
24
- class CommandOutputEvent(Event):
25
- """Event for command output display. Not persisted to session history."""
26
-
27
- command_name: CommandName | str
28
- content: str = ""
29
- ui_extra: model.ToolResultUIExtra | None = None
30
- is_error: bool = False
@@ -1,23 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from klaude_code.protocol import model
4
-
5
- from .base import Event
6
-
7
-
8
- class TaskStartEvent(Event):
9
- sub_agent_state: model.SubAgentState | None = None
10
- model_id: str | None = None
11
-
12
-
13
- class TaskFinishEvent(Event):
14
- task_result: str
15
- has_structured_output: bool = False
16
-
17
-
18
- class TurnStartEvent(Event):
19
- pass
20
-
21
-
22
- class TurnEndEvent(Event):
23
- pass
@@ -1,16 +0,0 @@
1
- """Metadata-related protocol events."""
2
-
3
- from __future__ import annotations
4
-
5
- from klaude_code.protocol import model
6
-
7
- from .base import Event, ResponseEvent
8
-
9
-
10
- class UsageEvent(ResponseEvent):
11
- usage: model.Usage
12
-
13
-
14
- class TaskMetadataEvent(Event):
15
- metadata: model.TaskMetadataItem
16
- cancelled: bool = False
@@ -1,43 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from .base import ResponseEvent
4
-
5
-
6
- class ThinkingStartEvent(ResponseEvent):
7
- pass
8
-
9
-
10
- class ThinkingDeltaEvent(ResponseEvent):
11
- content: str
12
-
13
-
14
- class ThinkingEndEvent(ResponseEvent):
15
- pass
16
-
17
-
18
- class AssistantTextStartEvent(ResponseEvent):
19
- pass
20
-
21
-
22
- class AssistantTextDeltaEvent(ResponseEvent):
23
- content: str
24
-
25
-
26
- class AssistantTextEndEvent(ResponseEvent):
27
- pass
28
-
29
-
30
- class AssistantImageDeltaEvent(ResponseEvent):
31
- file_path: str
32
-
33
-
34
- class ToolCallStartEvent(ResponseEvent):
35
- tool_call_id: str
36
- tool_name: str
37
-
38
-
39
- class ResponseCompleteEvent(ResponseEvent):
40
- """Final snapshot of the model response."""
41
-
42
- content: str
43
- thinking_text: str | None = None
@@ -1,56 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from pydantic import Field
4
-
5
- from klaude_code.protocol import llm_param
6
- from klaude_code.protocol.events.chat import DeveloperMessageEvent, UserMessageEvent
7
- from klaude_code.protocol.events.lifecycle import TaskFinishEvent, TaskStartEvent, TurnStartEvent
8
- from klaude_code.protocol.events.metadata import TaskMetadataEvent
9
- from klaude_code.protocol.events.streaming import AssistantImageDeltaEvent, ResponseCompleteEvent
10
- from klaude_code.protocol.events.tools import ToolCallEvent, ToolResultEvent
11
-
12
- from .base import Event
13
-
14
-
15
- class WelcomeEvent(Event):
16
- work_dir: str
17
- llm_config: llm_param.LLMConfigParameter
18
- show_klaude_code_info: bool = True
19
- loaded_skills: dict[str, list[str]] = Field(default_factory=dict)
20
-
21
-
22
- class ErrorEvent(Event):
23
- error_message: str
24
- can_retry: bool = False
25
-
26
-
27
- class InterruptEvent(Event):
28
- pass
29
-
30
-
31
- class EndEvent(Event):
32
- """Global display shutdown."""
33
-
34
- session_id: str = "__app__"
35
-
36
-
37
- type ReplayEventUnion = (
38
- TaskStartEvent
39
- | TaskFinishEvent
40
- | TurnStartEvent
41
- | AssistantImageDeltaEvent
42
- | ResponseCompleteEvent
43
- | ToolCallEvent
44
- | ToolResultEvent
45
- | UserMessageEvent
46
- | TaskMetadataEvent
47
- | InterruptEvent
48
- | DeveloperMessageEvent
49
- | ErrorEvent
50
- )
51
-
52
-
53
- class ReplayHistoryEvent(Event):
54
- events: list[ReplayEventUnion]
55
- updated_at: float
56
- is_load: bool = True
@@ -1,27 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import Literal
4
-
5
- from klaude_code.protocol import model
6
-
7
- from .base import ResponseEvent
8
-
9
-
10
- class ToolCallEvent(ResponseEvent):
11
- tool_call_id: str
12
- tool_name: str
13
- arguments: str
14
-
15
-
16
- class ToolResultEvent(ResponseEvent):
17
- tool_call_id: str
18
- tool_name: str
19
- result: str
20
- ui_extra: model.ToolResultUIExtra | None = None
21
- status: Literal["success", "error", "aborted"]
22
- task_metadata: model.TaskMetadata | None = None
23
- is_last_in_turn: bool = True
24
-
25
- @property
26
- def is_error(self) -> bool:
27
- return self.status in ("error", "aborted")