klaude-code 2.10.3__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.
- klaude_code/auth/AGENTS.md +4 -24
- klaude_code/auth/__init__.py +1 -17
- klaude_code/cli/auth_cmd.py +3 -53
- klaude_code/cli/list_model.py +0 -50
- klaude_code/config/assets/builtin_config.yaml +0 -28
- klaude_code/config/config.py +5 -42
- klaude_code/const.py +5 -2
- klaude_code/core/agent_profile.py +2 -10
- klaude_code/core/backtrack/__init__.py +3 -0
- klaude_code/core/backtrack/manager.py +48 -0
- klaude_code/core/memory.py +25 -9
- klaude_code/core/task.py +53 -7
- klaude_code/core/tool/__init__.py +2 -0
- klaude_code/core/tool/backtrack/__init__.py +3 -0
- klaude_code/core/tool/backtrack/backtrack_tool.md +17 -0
- klaude_code/core/tool/backtrack/backtrack_tool.py +65 -0
- klaude_code/core/tool/context.py +5 -0
- klaude_code/core/turn.py +3 -0
- klaude_code/llm/input_common.py +70 -1
- klaude_code/llm/openai_compatible/input.py +5 -2
- klaude_code/llm/openrouter/input.py +5 -2
- klaude_code/llm/registry.py +0 -1
- klaude_code/protocol/events.py +10 -0
- klaude_code/protocol/llm_param.py +0 -1
- klaude_code/protocol/message.py +10 -1
- klaude_code/protocol/tools.py +1 -0
- klaude_code/session/session.py +111 -2
- klaude_code/session/store.py +2 -0
- klaude_code/skill/assets/executing-plans/SKILL.md +84 -0
- klaude_code/skill/assets/writing-plans/SKILL.md +116 -0
- klaude_code/tui/commands.py +15 -0
- klaude_code/tui/components/developer.py +1 -1
- klaude_code/tui/components/rich/status.py +7 -76
- klaude_code/tui/components/rich/theme.py +10 -0
- klaude_code/tui/components/tools.py +31 -18
- klaude_code/tui/display.py +4 -0
- klaude_code/tui/input/prompt_toolkit.py +15 -1
- klaude_code/tui/machine.py +26 -8
- klaude_code/tui/renderer.py +97 -0
- klaude_code/tui/runner.py +7 -2
- klaude_code/tui/terminal/image.py +28 -12
- klaude_code/ui/terminal/title.py +8 -3
- {klaude_code-2.10.3.dist-info → klaude_code-2.10.4.dist-info}/METADATA +1 -1
- {klaude_code-2.10.3.dist-info → klaude_code-2.10.4.dist-info}/RECORD +46 -49
- klaude_code/auth/antigravity/__init__.py +0 -20
- klaude_code/auth/antigravity/exceptions.py +0 -17
- klaude_code/auth/antigravity/oauth.py +0 -315
- klaude_code/auth/antigravity/pkce.py +0 -25
- klaude_code/auth/antigravity/token_manager.py +0 -27
- klaude_code/core/prompts/prompt-antigravity.md +0 -80
- klaude_code/llm/antigravity/__init__.py +0 -3
- klaude_code/llm/antigravity/client.py +0 -558
- klaude_code/llm/antigravity/input.py +0 -268
- klaude_code/skill/assets/create-plan/SKILL.md +0 -74
- {klaude_code-2.10.3.dist-info → klaude_code-2.10.4.dist-info}/WHEEL +0 -0
- {klaude_code-2.10.3.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)
|
|
File without changes
|
|
File without changes
|