klaude-code 2.8.0__py3-none-any.whl → 2.8.1__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/main.py CHANGED
@@ -34,7 +34,7 @@ def _build_env_help() -> str:
34
34
  "Tool limits (Read):",
35
35
  " KLAUDE_READ_GLOBAL_LINE_CAP Max lines to read (default: 2000)",
36
36
  " KLAUDE_READ_MAX_CHARS Max total chars to read (default: 50000)",
37
- " KLAUDE_READ_MAX_IMAGE_BYTES Max image bytes to read (default: 4MB)",
37
+ " KLAUDE_READ_MAX_IMAGE_BYTES Max image bytes to read (default: 64MB)",
38
38
  " KLAUDE_IMAGE_OUTPUT_MAX_BYTES Max decoded image bytes (default: 64MB)",
39
39
  ]
40
40
  )
klaude_code/const.py CHANGED
@@ -81,7 +81,7 @@ MEMORY_FILE_NAMES = ["CLAUDE.md", "AGENTS.md", "AGENT.md"] # Memory file names
81
81
  READ_CHAR_LIMIT_PER_LINE = 2000 # Maximum characters per line before truncation
82
82
  READ_GLOBAL_LINE_CAP = _get_int_env("KLAUDE_READ_GLOBAL_LINE_CAP", 2000) # Maximum lines to read from a file
83
83
  READ_MAX_CHARS = _get_int_env("KLAUDE_READ_MAX_CHARS", 50000) # Maximum total characters to read
84
- READ_MAX_IMAGE_BYTES = _get_int_env("KLAUDE_READ_MAX_IMAGE_BYTES", 4 * 1024 * 1024) # Max image size (4MB)
84
+ READ_MAX_IMAGE_BYTES = _get_int_env("KLAUDE_READ_MAX_IMAGE_BYTES", 64 * 1024 * 1024) # Max image size (64MB)
85
85
  IMAGE_OUTPUT_MAX_BYTES = _get_int_env("KLAUDE_IMAGE_OUTPUT_MAX_BYTES", 64 * 1024 * 1024) # Max decoded image (64MB)
86
86
  BINARY_CHECK_SIZE = 8192 # Bytes to check for binary file detection
87
87
 
@@ -311,7 +311,7 @@ class DefaultModelProfileProvider(ModelProfileProvider):
311
311
  if is_image_model:
312
312
  agent_system_prompt: str | None = None
313
313
  agent_tools: list[llm_param.ToolSchema] = []
314
- agent_reminders: list[Reminder] = []
314
+ agent_reminders: list[Reminder] = [at_file_reader_reminder, image_reminder]
315
315
  else:
316
316
  agent_system_prompt = load_system_prompt(
317
317
  model_name, llm_client.protocol, sub_agent_type, config=self._config
@@ -268,9 +268,7 @@ def _call_args_probably_modify_file(args: dict[str, object]) -> bool:
268
268
  return True
269
269
  # Batch edits.
270
270
  edits = args.get("edits")
271
- if isinstance(edits, list):
272
- return True
273
- return False
271
+ return bool(isinstance(edits, list))
274
272
 
275
273
 
276
274
  def _collect_file_operations(
@@ -478,12 +476,12 @@ async def _build_summary(
478
476
  previous_summary,
479
477
  cancel,
480
478
  )
481
- if messages_to_summarize or previous_summary
482
- else asyncio.sleep(0, result="No prior history.")
479
+ if messages_to_summarize
480
+ else asyncio.sleep(0, result=previous_summary or "")
483
481
  )
484
482
  prefix_task = _generate_task_prefix_summary(task_prefix_messages, llm_client, config, cancel)
485
483
  history_summary, task_prefix_summary = await asyncio.gather(history_task, prefix_task)
486
- return f"{COMPACTION_SUMMARY_PREFIX}\n\n<summary>{history_summary}\n\n---\n\n**Task Context (split task):**\n\n{task_prefix_summary}\n\n</summary>"
484
+ return f"{COMPACTION_SUMMARY_PREFIX}\n\n<summary>{history_summary}\n\n---\n\n**Task Context (current task):**\n\n{task_prefix_summary}\n\n</summary>"
487
485
 
488
486
  return await _generate_summary(
489
487
  messages_to_summarize,
@@ -179,6 +179,21 @@ class AgentRuntime:
179
179
  )
180
180
  self._task_manager.register(operation.id, task, operation.session_id)
181
181
 
182
+ async def continue_agent(self, operation: op.ContinueAgentOperation) -> None:
183
+ """Continue agent execution without adding a new user message."""
184
+ agent = await self.ensure_agent(operation.session_id)
185
+
186
+ existing_active = self._task_manager.get(operation.id)
187
+ if existing_active is not None and not existing_active.task.done():
188
+ raise RuntimeError(f"Active task already registered for operation {operation.id}")
189
+
190
+ # Use empty input since we're continuing from existing history
191
+ empty_input = message.UserInputPayload(text="")
192
+ task: asyncio.Task[None] = asyncio.create_task(
193
+ self._run_agent_task(agent, empty_input, operation.id, operation.session_id)
194
+ )
195
+ self._task_manager.register(operation.id, task, operation.session_id)
196
+
182
197
  async def compact_session(self, operation: op.CompactSessionOperation) -> None:
183
198
  agent = await self.ensure_agent(operation.session_id)
184
199
 
@@ -525,6 +540,9 @@ class ExecutorContext:
525
540
  async def handle_run_agent(self, operation: op.RunAgentOperation) -> None:
526
541
  await self._agent_runtime.run_agent(operation)
527
542
 
543
+ async def handle_continue_agent(self, operation: op.ContinueAgentOperation) -> None:
544
+ await self._agent_runtime.continue_agent(operation)
545
+
528
546
  async def handle_compact_session(self, operation: op.CompactSessionOperation) -> None:
529
547
  await self._agent_runtime.compact_session(operation)
530
548
 
@@ -114,10 +114,9 @@ class EditTool(ToolABC):
114
114
  file_tracker = context.file_tracker
115
115
  tracked_status: model.FileStatus | None = None
116
116
  if not file_exists(file_path):
117
- # We require reading before editing
118
117
  return message.ToolResultMessage(
119
118
  status="error",
120
- output_text=("File has not been read yet. Read it first before writing to it."),
119
+ output_text=("File does not exist. If you want to create a file, use the Write tool instead."),
121
120
  )
122
121
  tracked_status = file_tracker.get(file_path)
123
122
  if tracked_status is None:
@@ -27,6 +27,7 @@ class CommandName(str, Enum):
27
27
  FORK_SESSION = "fork-session"
28
28
  RESUME = "resume"
29
29
  COPY = "copy"
30
+ CONTINUE = "continue"
30
31
 
31
32
  def __str__(self) -> str:
32
33
  return self.value
@@ -24,6 +24,7 @@ class OperationType(Enum):
24
24
  """Enumeration of supported operation types."""
25
25
 
26
26
  RUN_AGENT = "run_agent"
27
+ CONTINUE_AGENT = "continue_agent"
27
28
  COMPACT_SESSION = "compact_session"
28
29
  CHANGE_MODEL = "change_model"
29
30
  CHANGE_SUB_AGENT_MODEL = "change_sub_agent_model"
@@ -58,6 +59,19 @@ class RunAgentOperation(Operation):
58
59
  await handler.handle_run_agent(self)
59
60
 
60
61
 
62
+ class ContinueAgentOperation(Operation):
63
+ """Operation for continuing an agent task without adding a new user message.
64
+
65
+ Used for recovery after interruptions (network errors, API failures, etc.).
66
+ """
67
+
68
+ type: OperationType = OperationType.CONTINUE_AGENT
69
+ session_id: str
70
+
71
+ async def execute(self, handler: OperationHandler) -> None:
72
+ await handler.handle_continue_agent(self)
73
+
74
+
61
75
  class CompactSessionOperation(Operation):
62
76
  """Operation for compacting a session's conversation history."""
63
77
 
@@ -15,6 +15,7 @@ if TYPE_CHECKING:
15
15
  ChangeThinkingOperation,
16
16
  ClearSessionOperation,
17
17
  CompactSessionOperation,
18
+ ContinueAgentOperation,
18
19
  ExportSessionOperation,
19
20
  InitAgentOperation,
20
21
  InterruptOperation,
@@ -30,6 +31,10 @@ class OperationHandler(Protocol):
30
31
  """Handle a run agent operation."""
31
32
  ...
32
33
 
34
+ async def handle_continue_agent(self, operation: ContinueAgentOperation) -> None:
35
+ """Handle a continue agent operation (resume without adding user message)."""
36
+ ...
37
+
33
38
  async def handle_compact_session(self, operation: CompactSessionOperation) -> None:
34
39
  """Handle a compact session operation."""
35
40
  ...