tunacode-cli 0.0.30__py3-none-any.whl → 0.0.32__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.

Potentially problematic release.


This version of tunacode-cli might be problematic. Click here for more details.

api/auth.py ADDED
@@ -0,0 +1,13 @@
1
+ import jwt
2
+
3
+
4
+ def authenticate(username, password):
5
+ # TODO: Add password hashing
6
+ if username == "admin" and password == "admin":
7
+ return generate_token(username)
8
+ return None
9
+
10
+
11
+ def generate_token(username):
12
+ # TODO: Add expiration
13
+ return jwt.encode({"user": username}, "secret")
api/users.py ADDED
@@ -0,0 +1,8 @@
1
+ from .auth import authenticate
2
+
3
+
4
+ class UserManager:
5
+ def login(self, username, password):
6
+ token = authenticate(username, password)
7
+ # TODO: Store session
8
+ return token
tunacode/cli/commands.py CHANGED
@@ -72,44 +72,45 @@ class CommandSpec:
72
72
 
73
73
 
74
74
  class SimpleCommand(Command):
75
- """Base class for simple commands without complex logic."""
75
+ """Base class for simple commands without complex logic.
76
76
 
77
- def __init__(self, spec: CommandSpec):
78
- self.spec = spec
77
+ This class provides a standard implementation for commands that don't
78
+ require special initialization or complex behavior. It reads all
79
+ properties from a class-level CommandSpec attribute.
80
+ """
81
+
82
+ spec: CommandSpec
79
83
 
80
84
  @property
81
85
  def name(self) -> str:
82
86
  """The primary name of the command."""
83
- return self.spec.name
87
+ return self.__class__.spec.name
84
88
 
85
89
  @property
86
90
  def aliases(self) -> CommandArgs:
87
91
  """Alternative names/aliases for the command."""
88
- return self.spec.aliases
92
+ return self.__class__.spec.aliases
89
93
 
90
94
  @property
91
95
  def description(self) -> str:
92
96
  """Description of what the command does."""
93
- return self.spec.description
97
+ return self.__class__.spec.description
94
98
 
95
99
  @property
96
100
  def category(self) -> CommandCategory:
97
101
  """Category this command belongs to."""
98
- return self.spec.category
102
+ return self.__class__.spec.category
99
103
 
100
104
 
101
105
  class YoloCommand(SimpleCommand):
102
106
  """Toggle YOLO mode (skip confirmations)."""
103
107
 
104
- def __init__(self):
105
- super().__init__(
106
- CommandSpec(
107
- name="yolo",
108
- aliases=["/yolo"],
109
- description="Toggle YOLO mode (skip tool confirmations)",
110
- category=CommandCategory.DEVELOPMENT,
111
- )
112
- )
108
+ spec = CommandSpec(
109
+ name="yolo",
110
+ aliases=["/yolo"],
111
+ description="Toggle YOLO mode (skip tool confirmations)",
112
+ category=CommandCategory.DEVELOPMENT,
113
+ )
113
114
 
114
115
  async def execute(self, args: List[str], context: CommandContext) -> None:
115
116
  state = context.state_manager.session
@@ -123,15 +124,12 @@ class YoloCommand(SimpleCommand):
123
124
  class DumpCommand(SimpleCommand):
124
125
  """Dump message history."""
125
126
 
126
- def __init__(self):
127
- super().__init__(
128
- CommandSpec(
129
- name="dump",
130
- aliases=["/dump"],
131
- description="Dump the current message history",
132
- category=CommandCategory.DEBUG,
133
- )
134
- )
127
+ spec = CommandSpec(
128
+ name="dump",
129
+ aliases=["/dump"],
130
+ description="Dump the current message history",
131
+ category=CommandCategory.DEBUG,
132
+ )
135
133
 
136
134
  async def execute(self, args: List[str], context: CommandContext) -> None:
137
135
  await ui.dump_messages(context.state_manager.session.messages)
@@ -140,78 +138,46 @@ class DumpCommand(SimpleCommand):
140
138
  class ThoughtsCommand(SimpleCommand):
141
139
  """Toggle display of agent thoughts."""
142
140
 
143
- def __init__(self):
144
- super().__init__(
145
- CommandSpec(
146
- name="thoughts",
147
- aliases=["/thoughts"],
148
- description="Show or hide agent thought messages",
149
- category=CommandCategory.DEBUG,
150
- )
151
- )
141
+ spec = CommandSpec(
142
+ name="thoughts",
143
+ aliases=["/thoughts"],
144
+ description="Show or hide agent thought messages",
145
+ category=CommandCategory.DEBUG,
146
+ )
152
147
 
153
148
  async def execute(self, args: List[str], context: CommandContext) -> None:
154
149
  state = context.state_manager.session
155
- if args:
156
- arg = args[0].lower()
157
- if arg in {"on", "1", "true"}:
158
- state.show_thoughts = True
159
- elif arg in {"off", "0", "false"}:
160
- state.show_thoughts = False
161
- else:
162
- await ui.error("Usage: /thoughts [on|off]")
163
- return
164
- else:
165
- state.show_thoughts = not state.show_thoughts
166
- status = "ON" if state.show_thoughts else "OFF"
167
- await ui.success(f"Thought display {status}")
168
-
169
150
 
170
- class ArchitectCommand(SimpleCommand):
171
- """Toggle architect mode for task planning and orchestration."""
172
-
173
- def __init__(self):
174
- super().__init__(
175
- CommandSpec(
176
- name="architect",
177
- aliases=["/architect"],
178
- description="Toggle architect mode (task planning & orchestration)",
179
- category=CommandCategory.DEBUG,
180
- )
181
- )
151
+ # No args - toggle
152
+ if not args:
153
+ state.show_thoughts = not state.show_thoughts
154
+ status = "ON" if state.show_thoughts else "OFF"
155
+ await ui.success(f"Thought display {status}")
156
+ return
182
157
 
183
- async def execute(self, args: List[str], context: CommandContext) -> None:
184
- state = context.state_manager.session
185
- if args:
186
- arg = args[0].lower()
187
- if arg in {"on", "1", "true"}:
188
- state.architect_mode = True
189
- elif arg in {"off", "0", "false"}:
190
- state.architect_mode = False
191
- else:
192
- await ui.error("Usage: /architect [on|off]")
193
- return
194
- else:
195
- state.architect_mode = not getattr(state, "architect_mode", False)
196
- status = "ON" if state.architect_mode else "OFF"
197
- if state.architect_mode:
198
- await ui.success(f"Architect mode {status} - Requests will be planned before execution")
158
+ # Parse argument
159
+ arg = args[0].lower()
160
+ if arg in {"on", "1", "true"}:
161
+ state.show_thoughts = True
162
+ elif arg in {"off", "0", "false"}:
163
+ state.show_thoughts = False
199
164
  else:
200
- await ui.success(f"Architect mode {status} - Using direct execution")
165
+ await ui.error("Usage: /thoughts [on|off]")
166
+ return
167
+
168
+ status = "ON" if state.show_thoughts else "OFF"
169
+ await ui.success(f"Thought display {status}")
201
170
 
202
171
 
203
172
  class IterationsCommand(SimpleCommand):
204
173
  """Configure maximum agent iterations for ReAct reasoning."""
205
174
 
206
- def __init__(self):
207
- super().__init__(
208
- CommandSpec(
209
- name="iterations",
210
- aliases=["/iterations"],
211
- description="Set maximum agent iterations for complex reasoning",
212
- category=CommandCategory.DEBUG,
213
- )
214
- )
175
+ spec = CommandSpec(
176
+ name="iterations",
177
+ aliases=["/iterations"],
178
+ description="Set maximum agent iterations for complex reasoning",
179
+ category=CommandCategory.DEBUG,
180
+ )
215
181
 
216
182
  async def execute(self, args: List[str], context: CommandContext) -> None:
217
183
  state = context.state_manager.session
@@ -240,15 +206,12 @@ class IterationsCommand(SimpleCommand):
240
206
  class ClearCommand(SimpleCommand):
241
207
  """Clear screen and message history."""
242
208
 
243
- def __init__(self):
244
- super().__init__(
245
- CommandSpec(
246
- name="clear",
247
- aliases=["/clear"],
248
- description="Clear the screen and message history",
249
- category=CommandCategory.NAVIGATION,
250
- )
251
- )
209
+ spec = CommandSpec(
210
+ name="clear",
211
+ aliases=["/clear"],
212
+ description="Clear the screen and message history",
213
+ category=CommandCategory.NAVIGATION,
214
+ )
252
215
 
253
216
  async def execute(self, args: List[str], context: CommandContext) -> None:
254
217
  # Patch any orphaned tool calls before clearing
@@ -265,15 +228,12 @@ class ClearCommand(SimpleCommand):
265
228
  class FixCommand(SimpleCommand):
266
229
  """Fix orphaned tool calls that cause API errors."""
267
230
 
268
- def __init__(self):
269
- super().__init__(
270
- CommandSpec(
271
- name="fix",
272
- aliases=["/fix"],
273
- description="Fix orphaned tool calls causing API errors",
274
- category=CommandCategory.DEBUG,
275
- )
276
- )
231
+ spec = CommandSpec(
232
+ name="fix",
233
+ aliases=["/fix"],
234
+ description="Fix orphaned tool calls causing API errors",
235
+ category=CommandCategory.DEBUG,
236
+ )
277
237
 
278
238
  async def execute(self, args: List[str], context: CommandContext) -> None:
279
239
  from tunacode.core.agents.main import patch_tool_messages
@@ -298,17 +258,12 @@ class FixCommand(SimpleCommand):
298
258
  class ParseToolsCommand(SimpleCommand):
299
259
  """Parse and execute JSON tool calls from the last response."""
300
260
 
301
- def __init__(self):
302
- super().__init__(
303
- CommandSpec(
304
- name="parsetools",
305
- aliases=["/parsetools"],
306
- description=(
307
- "Parse JSON tool calls from last response when structured calling fails"
308
- ),
309
- category=CommandCategory.DEBUG,
310
- )
311
- )
261
+ spec = CommandSpec(
262
+ name="parsetools",
263
+ aliases=["/parsetools"],
264
+ description=("Parse JSON tool calls from last response when structured calling fails"),
265
+ category=CommandCategory.DEBUG,
266
+ )
312
267
 
313
268
  async def execute(self, args: List[str], context: CommandContext) -> None:
314
269
  from tunacode.core.agents.main import extract_and_execute_tool_calls
@@ -349,15 +304,12 @@ class ParseToolsCommand(SimpleCommand):
349
304
  class RefreshConfigCommand(SimpleCommand):
350
305
  """Refresh configuration from defaults."""
351
306
 
352
- def __init__(self):
353
- super().__init__(
354
- CommandSpec(
355
- name="refresh",
356
- aliases=["/refresh"],
357
- description="Refresh configuration from defaults (useful after updates)",
358
- category=CommandCategory.SYSTEM,
359
- )
360
- )
307
+ spec = CommandSpec(
308
+ name="refresh",
309
+ aliases=["/refresh"],
310
+ description="Refresh configuration from defaults (useful after updates)",
311
+ category=CommandCategory.SYSTEM,
312
+ )
361
313
 
362
314
  async def execute(self, args: List[str], context: CommandContext) -> None:
363
315
  from tunacode.configuration.defaults import DEFAULT_USER_CONFIG
@@ -379,76 +331,17 @@ class RefreshConfigCommand(SimpleCommand):
379
331
  await ui.success(f"Configuration refreshed - max iterations: {max_iterations}")
380
332
 
381
333
 
382
- class TunaCodeCommand(SimpleCommand):
383
- """Use BM25 to inspect the codebase and read relevant files."""
384
-
385
- def __init__(self):
386
- super().__init__(
387
- CommandSpec(
388
- name="tunaCode",
389
- aliases=["/tunaCode"],
390
- description="Scan repo with BM25 and display key files",
391
- category=CommandCategory.DEVELOPMENT,
392
- )
393
- )
394
-
395
- async def execute(self, args: List[str], context: CommandContext) -> None:
396
- from pathlib import Path
397
-
398
- from tunacode.constants import UI_COLORS
399
- from tunacode.utils.file_utils import DotDict
400
-
401
- from ..tools.read_file import read_file
402
- from ..utils.bm25 import BM25, tokenize
403
- from ..utils.text_utils import ext_to_lang
404
-
405
- colors = DotDict(UI_COLORS)
406
-
407
- query = " ".join(args) if args else "overview"
408
- await ui.info("Building BM25 index of repository")
409
-
410
- docs: List[str] = []
411
- paths: List[Path] = []
412
- exts = {".py", ".js", ".ts", ".java", ".c", ".cpp", ".md", ".txt"}
413
- for path in Path(".").rglob("*"):
414
- if path.is_file() and path.suffix in exts:
415
- try:
416
- docs.append(path.read_text(encoding="utf-8"))
417
- paths.append(path)
418
- except Exception:
419
- continue
420
-
421
- if not docs:
422
- await ui.error("No files found to index")
423
- return
424
-
425
- bm25 = BM25(docs)
426
- scores = bm25.get_scores(tokenize(query))
427
- ranked = sorted(range(len(scores)), key=lambda i: scores[i], reverse=True)[:5]
428
-
429
- for idx in ranked:
430
- file_path = paths[idx]
431
- content = await read_file(str(file_path))
432
- lang = ext_to_lang(str(file_path))
433
- await ui.panel(
434
- str(file_path),
435
- f"```{lang}\n{content}\n```",
436
- border_style=colors.muted,
437
- )
438
-
439
-
440
334
  class HelpCommand(SimpleCommand):
441
335
  """Show help information."""
442
336
 
337
+ spec = CommandSpec(
338
+ name="help",
339
+ aliases=["/help"],
340
+ description="Show help information",
341
+ category=CommandCategory.SYSTEM,
342
+ )
343
+
443
344
  def __init__(self, command_registry=None):
444
- super().__init__(
445
- CommandSpec(
446
- name="help",
447
- aliases=["/help"],
448
- description="Show help information",
449
- category=CommandCategory.SYSTEM,
450
- )
451
- )
452
345
  self._command_registry = command_registry
453
346
 
454
347
  async def execute(self, args: List[str], context: CommandContext) -> None:
@@ -458,15 +351,12 @@ class HelpCommand(SimpleCommand):
458
351
  class BranchCommand(SimpleCommand):
459
352
  """Create and switch to a new git branch."""
460
353
 
461
- def __init__(self):
462
- super().__init__(
463
- CommandSpec(
464
- name="branch",
465
- aliases=["/branch"],
466
- description="Create and switch to a new git branch",
467
- category=CommandCategory.DEVELOPMENT,
468
- )
469
- )
354
+ spec = CommandSpec(
355
+ name="branch",
356
+ aliases=["/branch"],
357
+ description="Create and switch to a new git branch",
358
+ category=CommandCategory.DEVELOPMENT,
359
+ )
470
360
 
471
361
  async def execute(self, args: List[str], context: CommandContext) -> None:
472
362
  import os
@@ -503,15 +393,14 @@ class BranchCommand(SimpleCommand):
503
393
  class CompactCommand(SimpleCommand):
504
394
  """Compact conversation context."""
505
395
 
396
+ spec = CommandSpec(
397
+ name="compact",
398
+ aliases=["/compact"],
399
+ description="Summarize and compact the conversation history",
400
+ category=CommandCategory.SYSTEM,
401
+ )
402
+
506
403
  def __init__(self, process_request_callback: Optional[ProcessRequestCallback] = None):
507
- super().__init__(
508
- CommandSpec(
509
- name="compact",
510
- aliases=["/compact"],
511
- description="Summarize and compact the conversation history",
512
- category=CommandCategory.SYSTEM,
513
- )
514
- )
515
404
  self._process_request = process_request_callback
516
405
 
517
406
  async def execute(self, args: List[str], context: CommandContext) -> None:
@@ -612,15 +501,12 @@ class CompactCommand(SimpleCommand):
612
501
  class UpdateCommand(SimpleCommand):
613
502
  """Update TunaCode to the latest version."""
614
503
 
615
- def __init__(self):
616
- super().__init__(
617
- CommandSpec(
618
- name="update",
619
- aliases=["/update"],
620
- description="Update TunaCode to the latest version",
621
- category=CommandCategory.SYSTEM,
622
- )
623
- )
504
+ spec = CommandSpec(
505
+ name="update",
506
+ aliases=["/update"],
507
+ description="Update TunaCode to the latest version",
508
+ category=CommandCategory.SYSTEM,
509
+ )
624
510
 
625
511
  async def execute(self, args: List[str], context: CommandContext) -> None:
626
512
  import shutil
@@ -706,19 +592,16 @@ class UpdateCommand(SimpleCommand):
706
592
  class ModelCommand(SimpleCommand):
707
593
  """Manage model selection."""
708
594
 
709
- def __init__(self):
710
- super().__init__(
711
- CommandSpec(
712
- name="model",
713
- aliases=["/model"],
714
- description="Switch model (e.g., /model gpt-4 or /model openai:gpt-4)",
715
- category=CommandCategory.MODEL,
716
- )
717
- )
595
+ spec = CommandSpec(
596
+ name="model",
597
+ aliases=["/model"],
598
+ description="Switch model (e.g., /model gpt-4 or /model openai:gpt-4)",
599
+ category=CommandCategory.MODEL,
600
+ )
718
601
 
719
602
  async def execute(self, args: CommandArgs, context: CommandContext) -> Optional[str]:
603
+ # No arguments - show current model
720
604
  if not args:
721
- # No arguments - show current model
722
605
  current_model = context.state_manager.session.current_model
723
606
  await ui.info(f"Current model: {current_model}")
724
607
  await ui.muted("Usage: /model <provider:model-name> [default]")
@@ -748,10 +631,10 @@ class ModelCommand(SimpleCommand):
748
631
  utils.user_configuration.set_default_model(model_name, context.state_manager)
749
632
  await ui.muted("Updating default model")
750
633
  return "restart"
751
- else:
752
- # Show success message with the new model
753
- await ui.success(f"Switched to model: {model_name}")
754
- return None
634
+
635
+ # Show success message with the new model
636
+ await ui.success(f"Switched to model: {model_name}")
637
+ return None
755
638
 
756
639
 
757
640
  @dataclass
@@ -833,7 +716,6 @@ class CommandRegistry:
833
716
  YoloCommand,
834
717
  DumpCommand,
835
718
  ThoughtsCommand,
836
- ArchitectCommand,
837
719
  IterationsCommand,
838
720
  ClearCommand,
839
721
  FixCommand,
@@ -842,7 +724,6 @@ class CommandRegistry:
842
724
  UpdateCommand,
843
725
  HelpCommand,
844
726
  BranchCommand,
845
- # TunaCodeCommand, # TODO: Temporarily disabled
846
727
  CompactCommand,
847
728
  ModelCommand,
848
729
  ]
tunacode/cli/repl.py CHANGED
@@ -18,7 +18,6 @@ from pydantic_ai.exceptions import UnexpectedModelBehavior
18
18
  from tunacode.configuration.settings import ApplicationSettings
19
19
  from tunacode.core.agents import main as agent
20
20
  from tunacode.core.agents.main import patch_tool_messages
21
- from tunacode.core.agents.orchestrator import OrchestratorAgent
22
21
  from tunacode.core.tool_handler import ToolHandler
23
22
  from tunacode.exceptions import AgentError, UserAbortError, ValidationError
24
23
  from tunacode.ui import console as ui
@@ -179,93 +178,50 @@ async def process_request(text: str, state_manager: StateManager, output: bool =
179
178
  def tool_callback_with_state(part, node):
180
179
  return _tool_handler(part, node, state_manager)
181
180
 
182
- # Check if architect mode is enabled
183
- if getattr(state_manager.session, "architect_mode", False):
184
- # Expand @file references before sending to the orchestrator
185
- try:
186
- from tunacode.utils.text_utils import expand_file_refs
187
-
188
- text, referenced_files = expand_file_refs(text)
189
- # Track the referenced files
190
- for file_path in referenced_files:
191
- state_manager.session.files_in_context.add(file_path)
192
- except ValueError as e:
193
- await ui.error(str(e))
194
- return
195
- # Use orchestrator for planning and execution
196
- orchestrator = OrchestratorAgent(state_manager)
197
- results = await orchestrator.run(text, state_manager.session.current_model)
198
-
199
- if output:
200
- # Process results from all sub-agents
201
- for res in results:
202
- # Check if result exists and has output
203
- if (
204
- hasattr(res, "result")
205
- and res.result is not None
206
- and hasattr(res.result, "output")
207
- ):
208
- await ui.agent(res.result.output)
209
-
210
- if not results:
211
- # Fallback: show that the request was processed
212
- await ui.muted("Request completed")
213
-
214
- # Always show files in context after orchestrator response
181
+ # Expand @file references before sending to the agent
182
+ try:
183
+ from tunacode.utils.text_utils import expand_file_refs
184
+
185
+ text, referenced_files = expand_file_refs(text)
186
+ # Track the referenced files
187
+ for file_path in referenced_files:
188
+ state_manager.session.files_in_context.add(file_path)
189
+ except ValueError as e:
190
+ await ui.error(str(e))
191
+ return
192
+
193
+ # Use normal agent processing
194
+ res = await agent.process_request(
195
+ state_manager.session.current_model,
196
+ text,
197
+ state_manager,
198
+ tool_callback=tool_callback_with_state,
199
+ )
200
+ if output:
201
+ if state_manager.session.show_thoughts:
202
+ new_msgs = state_manager.session.messages[start_idx:]
203
+ for msg in new_msgs:
204
+ if isinstance(msg, dict) and "thought" in msg:
205
+ await ui.muted(f"THOUGHT: {msg['thought']}")
206
+ # Check if result exists and has output
207
+ if hasattr(res, "result") and res.result is not None and hasattr(res.result, "output"):
208
+ await ui.agent(res.result.output)
209
+ # Always show files in context after agent response
215
210
  if state_manager.session.files_in_context:
211
+ # Extract just filenames from full paths for readability
216
212
  filenames = [
217
213
  Path(f).name for f in sorted(state_manager.session.files_in_context)
218
214
  ]
219
215
  await ui.muted(f"\nFiles in context: {', '.join(filenames)}")
220
- else:
221
- # Expand @file references before sending to the agent
222
- try:
223
- from tunacode.utils.text_utils import expand_file_refs
224
-
225
- text, referenced_files = expand_file_refs(text)
226
- # Track the referenced files
227
- for file_path in referenced_files:
228
- state_manager.session.files_in_context.add(file_path)
229
- except ValueError as e:
230
- await ui.error(str(e))
231
- return
232
-
233
- # Use normal agent processing
234
- res = await agent.process_request(
235
- state_manager.session.current_model,
236
- text,
237
- state_manager,
238
- tool_callback=tool_callback_with_state,
239
- )
240
- if output:
241
- if state_manager.session.show_thoughts:
242
- new_msgs = state_manager.session.messages[start_idx:]
243
- for msg in new_msgs:
244
- if isinstance(msg, dict) and "thought" in msg:
245
- await ui.muted(f"THOUGHT: {msg['thought']}")
246
- # Check if result exists and has output
247
- if (
248
- hasattr(res, "result")
249
- and res.result is not None
250
- and hasattr(res.result, "output")
251
- ):
252
- await ui.agent(res.result.output)
253
- # Always show files in context after agent response
254
- if state_manager.session.files_in_context:
255
- # Extract just filenames from full paths for readability
256
- filenames = [
257
- Path(f).name for f in sorted(state_manager.session.files_in_context)
258
- ]
259
- await ui.muted(f"\nFiles in context: {', '.join(filenames)}")
260
- else:
261
- # Fallback: show that the request was processed
262
- await ui.muted("Request completed")
263
- # Show files in context even for empty responses
264
- if state_manager.session.files_in_context:
265
- filenames = [
266
- Path(f).name for f in sorted(state_manager.session.files_in_context)
267
- ]
268
- await ui.muted(f"Files in context: {', '.join(filenames)}")
216
+ else:
217
+ # Fallback: show that the request was processed
218
+ await ui.muted("Request completed")
219
+ # Show files in context even for empty responses
220
+ if state_manager.session.files_in_context:
221
+ filenames = [
222
+ Path(f).name for f in sorted(state_manager.session.files_in_context)
223
+ ]
224
+ await ui.muted(f"Files in context: {', '.join(filenames)}")
269
225
  except CancelledError:
270
226
  await ui.muted("Request cancelled")
271
227
  except UserAbortError:
@@ -294,7 +250,7 @@ async def process_request(text: str, state_manager: StateManager, output: bool =
294
250
  await extract_and_execute_tool_calls(
295
251
  part.content, tool_callback_with_state, state_manager
296
252
  )
297
- await ui.warning("🔧 Recovered using JSON tool parsing")
253
+ await ui.warning(" Recovered using JSON tool parsing")
298
254
  return # Successfully recovered
299
255
  except Exception:
300
256
  pass # Fallback failed, continue with normal error handling