klaude-code 2.10.2__py3-none-any.whl → 2.10.4__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 (63) hide show
  1. klaude_code/auth/AGENTS.md +4 -24
  2. klaude_code/auth/__init__.py +1 -17
  3. klaude_code/cli/auth_cmd.py +3 -53
  4. klaude_code/cli/list_model.py +0 -50
  5. klaude_code/config/assets/builtin_config.yaml +7 -35
  6. klaude_code/config/config.py +5 -42
  7. klaude_code/const.py +5 -2
  8. klaude_code/core/agent_profile.py +2 -10
  9. klaude_code/core/backtrack/__init__.py +3 -0
  10. klaude_code/core/backtrack/manager.py +48 -0
  11. klaude_code/core/memory.py +25 -9
  12. klaude_code/core/task.py +53 -7
  13. klaude_code/core/tool/__init__.py +2 -0
  14. klaude_code/core/tool/backtrack/__init__.py +3 -0
  15. klaude_code/core/tool/backtrack/backtrack_tool.md +17 -0
  16. klaude_code/core/tool/backtrack/backtrack_tool.py +65 -0
  17. klaude_code/core/tool/context.py +5 -0
  18. klaude_code/core/turn.py +3 -0
  19. klaude_code/llm/anthropic/input.py +28 -4
  20. klaude_code/llm/input_common.py +70 -1
  21. klaude_code/llm/openai_compatible/input.py +5 -2
  22. klaude_code/llm/openrouter/input.py +5 -2
  23. klaude_code/llm/registry.py +0 -1
  24. klaude_code/protocol/events.py +10 -0
  25. klaude_code/protocol/llm_param.py +0 -1
  26. klaude_code/protocol/message.py +10 -1
  27. klaude_code/protocol/tools.py +1 -0
  28. klaude_code/session/session.py +111 -2
  29. klaude_code/session/store.py +2 -0
  30. klaude_code/skill/assets/executing-plans/SKILL.md +84 -0
  31. klaude_code/skill/assets/writing-plans/SKILL.md +116 -0
  32. klaude_code/tui/commands.py +15 -0
  33. klaude_code/tui/components/developer.py +1 -1
  34. klaude_code/tui/components/errors.py +2 -4
  35. klaude_code/tui/components/metadata.py +5 -10
  36. klaude_code/tui/components/rich/markdown.py +5 -1
  37. klaude_code/tui/components/rich/status.py +7 -76
  38. klaude_code/tui/components/rich/theme.py +12 -2
  39. klaude_code/tui/components/tools.py +31 -18
  40. klaude_code/tui/components/user_input.py +1 -1
  41. klaude_code/tui/display.py +4 -0
  42. klaude_code/tui/input/completers.py +51 -17
  43. klaude_code/tui/input/images.py +127 -0
  44. klaude_code/tui/input/prompt_toolkit.py +16 -2
  45. klaude_code/tui/machine.py +26 -8
  46. klaude_code/tui/renderer.py +97 -0
  47. klaude_code/tui/runner.py +7 -2
  48. klaude_code/tui/terminal/image.py +28 -12
  49. klaude_code/ui/terminal/title.py +8 -3
  50. {klaude_code-2.10.2.dist-info → klaude_code-2.10.4.dist-info}/METADATA +1 -1
  51. {klaude_code-2.10.2.dist-info → klaude_code-2.10.4.dist-info}/RECORD +53 -56
  52. klaude_code/auth/antigravity/__init__.py +0 -20
  53. klaude_code/auth/antigravity/exceptions.py +0 -17
  54. klaude_code/auth/antigravity/oauth.py +0 -315
  55. klaude_code/auth/antigravity/pkce.py +0 -25
  56. klaude_code/auth/antigravity/token_manager.py +0 -27
  57. klaude_code/core/prompts/prompt-antigravity.md +0 -80
  58. klaude_code/llm/antigravity/__init__.py +0 -3
  59. klaude_code/llm/antigravity/client.py +0 -558
  60. klaude_code/llm/antigravity/input.py +0 -268
  61. klaude_code/skill/assets/create-plan/SKILL.md +0 -74
  62. {klaude_code-2.10.2.dist-info → klaude_code-2.10.4.dist-info}/WHEEL +0 -0
  63. {klaude_code-2.10.2.dist-info → klaude_code-2.10.4.dist-info}/entry_points.txt +0 -0
@@ -1,268 +0,0 @@
1
- """Message conversion utilities for Antigravity Cloud Code Assist API."""
2
-
3
- import json
4
- from base64 import b64decode
5
- from binascii import Error as BinasciiError
6
- from typing import Any, TypedDict
7
-
8
- from klaude_code.const import EMPTY_TOOL_OUTPUT_MESSAGE
9
- from klaude_code.llm.image import assistant_image_to_data_url, image_file_to_data_url, parse_data_url
10
- from klaude_code.llm.input_common import (
11
- DeveloperAttachment,
12
- ImagePart,
13
- attach_developer_messages,
14
- merge_reminder_text,
15
- split_thinking_parts,
16
- )
17
- from klaude_code.protocol import llm_param, message
18
-
19
-
20
- class InlineData(TypedDict, total=False):
21
- mimeType: str
22
- data: str
23
-
24
-
25
- class FunctionCall(TypedDict, total=False):
26
- id: str
27
- name: str
28
- args: dict[str, Any]
29
-
30
-
31
- class FunctionResponse(TypedDict, total=False):
32
- id: str
33
- name: str
34
- response: dict[str, Any]
35
- parts: list[dict[str, Any]]
36
-
37
-
38
- class Part(TypedDict, total=False):
39
- text: str
40
- thought: bool
41
- thoughtSignature: str
42
- inlineData: InlineData
43
- functionCall: FunctionCall
44
- functionResponse: FunctionResponse
45
-
46
-
47
- class Content(TypedDict):
48
- role: str
49
- parts: list[Part]
50
-
51
-
52
- class FunctionDeclaration(TypedDict, total=False):
53
- name: str
54
- description: str
55
- parameters: dict[str, Any]
56
-
57
-
58
- class Tool(TypedDict):
59
- functionDeclarations: list[FunctionDeclaration]
60
-
61
-
62
- def _data_url_to_inline_data(url: str) -> InlineData:
63
- """Convert data URL to inline_data dict."""
64
- media_type, _, decoded = parse_data_url(url)
65
- import base64
66
-
67
- return InlineData(mimeType=media_type, data=base64.b64encode(decoded).decode("ascii"))
68
-
69
-
70
- def _image_part_to_part(image: ImagePart) -> Part:
71
- """Convert ImageURLPart or ImageFilePart to Part dict."""
72
- url = image_file_to_data_url(image) if isinstance(image, message.ImageFilePart) else image.url
73
- if url.startswith("data:"):
74
- return Part(inlineData=_data_url_to_inline_data(url))
75
- # For non-data URLs, best-effort using inline_data format
76
- return Part(text=f"[Image: {url}]")
77
-
78
-
79
- def _user_message_to_content(msg: message.UserMessage, attachment: DeveloperAttachment) -> Content:
80
- """Convert UserMessage to Content dict."""
81
- parts: list[Part] = []
82
- for part in msg.parts:
83
- if isinstance(part, message.TextPart):
84
- parts.append(Part(text=part.text))
85
- elif isinstance(part, (message.ImageURLPart, message.ImageFilePart)):
86
- parts.append(_image_part_to_part(part))
87
- if attachment.text:
88
- parts.append(Part(text=attachment.text))
89
- for image in attachment.images:
90
- parts.append(_image_part_to_part(image))
91
- if not parts:
92
- parts.append(Part(text=""))
93
- return Content(role="user", parts=parts)
94
-
95
-
96
- def _tool_messages_to_contents(
97
- msgs: list[tuple[message.ToolResultMessage, DeveloperAttachment]], model_name: str | None
98
- ) -> list[Content]:
99
- """Convert tool result messages to Content dicts."""
100
- supports_multimodal_function_response = bool(model_name and "gemini-3" in model_name.lower())
101
-
102
- response_parts: list[Part] = []
103
- extra_image_contents: list[Content] = []
104
-
105
- for msg, attachment in msgs:
106
- merged_text = merge_reminder_text(
107
- msg.output_text or EMPTY_TOOL_OUTPUT_MESSAGE,
108
- attachment.text,
109
- )
110
- has_text = merged_text.strip() != ""
111
-
112
- images: list[ImagePart] = [
113
- part for part in msg.parts if isinstance(part, (message.ImageURLPart, message.ImageFilePart))
114
- ]
115
- images.extend(attachment.images)
116
- image_parts: list[Part] = []
117
- function_response_parts: list[dict[str, Any]] = []
118
-
119
- for image in images:
120
- try:
121
- image_parts.append(_image_part_to_part(image))
122
- if isinstance(image, message.ImageFilePart):
123
- inline_data = _data_url_to_inline_data(image_file_to_data_url(image))
124
- function_response_parts.append({"inlineData": inline_data})
125
- elif image.url.startswith("data:"):
126
- inline_data = _data_url_to_inline_data(image.url)
127
- function_response_parts.append({"inlineData": inline_data})
128
- except ValueError:
129
- continue
130
-
131
- has_images = len(image_parts) > 0
132
- response_value = merged_text if has_text else "(see attached image)" if has_images else ""
133
- response_payload = {"error": response_value} if msg.status != "success" else {"output": response_value}
134
-
135
- function_response = FunctionResponse(
136
- id=msg.call_id,
137
- name=msg.tool_name,
138
- response=response_payload,
139
- )
140
- if has_images and supports_multimodal_function_response:
141
- function_response["parts"] = function_response_parts
142
-
143
- response_parts.append(Part(functionResponse=function_response))
144
-
145
- if has_images and not supports_multimodal_function_response:
146
- extra_image_contents.append(Content(role="user", parts=[Part(text="Tool result image:"), *image_parts]))
147
-
148
- contents: list[Content] = []
149
- if response_parts:
150
- contents.append(Content(role="user", parts=response_parts))
151
- contents.extend(extra_image_contents)
152
- return contents
153
-
154
-
155
- def _decode_thought_signature(sig: str | None) -> str | None:
156
- """Validate base64 thought signature."""
157
- if not sig:
158
- return None
159
- try:
160
- b64decode(sig)
161
- return sig
162
- except (BinasciiError, ValueError):
163
- return None
164
-
165
-
166
- def _assistant_message_to_content(msg: message.AssistantMessage, model_name: str | None) -> Content | None:
167
- """Convert AssistantMessage to Content dict."""
168
- parts: list[Part] = []
169
- native_thinking_parts, degraded_thinking_texts = split_thinking_parts(msg, model_name)
170
- native_thinking_ids = {id(part) for part in native_thinking_parts}
171
-
172
- for part in msg.parts:
173
- if isinstance(part, message.ThinkingTextPart):
174
- if id(part) not in native_thinking_ids:
175
- continue
176
- parts.append(Part(text=part.text, thought=True))
177
-
178
- elif isinstance(part, message.ThinkingSignaturePart):
179
- if id(part) not in native_thinking_ids:
180
- continue
181
- if not part.signature or part.format != "google":
182
- continue
183
- # Attach signature to the previous part
184
- if parts:
185
- sig = _decode_thought_signature(part.signature)
186
- if sig:
187
- parts[-1]["thoughtSignature"] = sig
188
-
189
- elif isinstance(part, message.TextPart):
190
- # Skip empty text blocks
191
- if not part.text or part.text.strip() == "":
192
- continue
193
- parts.append(Part(text=part.text))
194
-
195
- elif isinstance(part, message.ToolCallPart):
196
- args: dict[str, Any]
197
- if part.arguments_json:
198
- try:
199
- args = json.loads(part.arguments_json)
200
- except json.JSONDecodeError:
201
- args = {"_raw": part.arguments_json}
202
- else:
203
- args = {}
204
- parts.append(Part(functionCall=FunctionCall(id=part.call_id, name=part.tool_name, args=args)))
205
-
206
- elif isinstance(part, message.ImageFilePart):
207
- try:
208
- data_url = assistant_image_to_data_url(part)
209
- parts.append(_image_part_to_part(message.ImageURLPart(url=data_url)))
210
- except (ValueError, FileNotFoundError):
211
- pass
212
-
213
- if degraded_thinking_texts:
214
- parts.insert(0, Part(text="<thinking>\n" + "\n".join(degraded_thinking_texts) + "\n</thinking>"))
215
-
216
- if not parts:
217
- return None
218
- return Content(role="model", parts=parts)
219
-
220
-
221
- def convert_history_to_contents(
222
- history: list[message.Message],
223
- model_name: str | None,
224
- ) -> list[Content]:
225
- """Convert message history to Cloud Code Assist Content format."""
226
- contents: list[Content] = []
227
- pending_tool_messages: list[tuple[message.ToolResultMessage, DeveloperAttachment]] = []
228
-
229
- def flush_tool_messages() -> None:
230
- nonlocal pending_tool_messages
231
- if pending_tool_messages:
232
- contents.extend(_tool_messages_to_contents(pending_tool_messages, model_name=model_name))
233
- pending_tool_messages = []
234
-
235
- for msg, attachment in attach_developer_messages(history):
236
- match msg:
237
- case message.ToolResultMessage():
238
- pending_tool_messages.append((msg, attachment))
239
- case message.UserMessage():
240
- flush_tool_messages()
241
- contents.append(_user_message_to_content(msg, attachment))
242
- case message.AssistantMessage():
243
- flush_tool_messages()
244
- content = _assistant_message_to_content(msg, model_name=model_name)
245
- if content is not None:
246
- contents.append(content)
247
- case message.SystemMessage():
248
- continue
249
- case _:
250
- continue
251
-
252
- flush_tool_messages()
253
- return contents
254
-
255
-
256
- def convert_tool_schema(tools: list[llm_param.ToolSchema] | None) -> list[Tool] | None:
257
- """Convert tool schemas to Cloud Code Assist Tool format."""
258
- if tools is None or len(tools) == 0:
259
- return None
260
- declarations = [
261
- FunctionDeclaration(
262
- name=tool.name,
263
- description=tool.description,
264
- parameters=dict(tool.parameters) if tool.parameters else {},
265
- )
266
- for tool in tools
267
- ]
268
- return [Tool(functionDeclarations=declarations)]
@@ -1,74 +0,0 @@
1
- ---
2
- name: create-plan
3
- description: Create a concise plan. Use when a user explicitly asks for a plan related to a coding task.
4
- metadata:
5
- short-description: Create a plan
6
- ---
7
-
8
- # Create Plan
9
-
10
- ## Goal
11
-
12
- Turn a user prompt into a **single, actionable plan** delivered in the final assistant message.
13
-
14
- ## Minimal workflow
15
-
16
- Throughout the entire workflow, operate in read-only mode. Do not write or update files.
17
-
18
- 1. **Scan context quickly**
19
- - Read `README.md` and any obvious docs (`docs/`, `CONTRIBUTING.md`, `ARCHITECTURE.md`).
20
- - Skim relevant files (the ones most likely touched).
21
- - Identify constraints (language, frameworks, CI/test commands, deployment shape).
22
-
23
- 2. **Ask follow-ups only if blocking**
24
- - Ask **at most 1–2 questions**.
25
- - Only ask if you cannot responsibly plan without the answer; prefer multiple-choice.
26
- - If unsure but not blocked, make a reasonable assumption and proceed.
27
-
28
- 3. **Create a plan using the template below**
29
- - Start with **1 short paragraph** describing the intent and approach.
30
- - Clearly call out what is **in scope** and what is **not in scope** in short.
31
- - Then provide a **small checklist** of action items (default 6–10 items).
32
- - Each checklist item should be a concrete action and, when helpful, mention files/commands.
33
- - **Make items atomic and ordered**: discovery → changes → tests → rollout.
34
- - **Verb-first**: “Add…”, “Refactor…”, “Verify…”, “Ship…”.
35
- - Include at least one item for **tests/validation** and one for **edge cases/risk** when applicable.
36
- - If there are unknowns, include a tiny **Open questions** section (max 3).
37
-
38
- 4. **Do not preface the plan with meta explanations; output only the plan as per template**
39
-
40
- ## Plan template (follow exactly)
41
-
42
- ```markdown
43
- # Plan
44
-
45
- <1–3 sentences: what we’re doing, why, and the high-level approach.>
46
-
47
- ## Scope
48
- - In:
49
- - Out:
50
-
51
- ## Action items
52
- - [ ] <Step 1>
53
- - [ ] <Step 2>
54
- - [ ] <Step 3>
55
- - [ ] <Step 4>
56
- - [ ] <Step 5>
57
- - [ ] <Step 6>
58
-
59
- ## Open questions
60
- - <Question 1>
61
- - <Question 2>
62
- - <Question 3>
63
- ```
64
-
65
- ## Checklist item guidance
66
- Good checklist items:
67
- - Point to likely files/modules: src/..., app/..., services/...
68
- - Name concrete validation: “Run npm test”, “Add unit tests for X”
69
- - Include safe rollout when relevant: feature flag, migration plan, rollback note
70
-
71
- Avoid:
72
- - Vague steps (“handle backend”, “do auth”)
73
- - Too many micro-steps
74
- - Writing code snippets (keep the plan implementation-agnostic)