kubrick-cli 0.1.2__tar.gz → 0.1.4__tar.gz

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 (42) hide show
  1. kubrick_cli-0.1.4/PKG-INFO +137 -0
  2. kubrick_cli-0.1.4/README.md +113 -0
  3. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/agent_loop.py +4 -37
  4. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/classifier.py +0 -4
  5. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/config.py +14 -15
  6. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/display.py +5 -16
  7. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/execution_strategy.py +4 -6
  8. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/main.py +119 -110
  9. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/planning.py +15 -24
  10. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/progress.py +3 -13
  11. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/providers/anthropic_provider.py +0 -15
  12. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/providers/base.py +0 -1
  13. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/providers/factory.py +5 -27
  14. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/providers/openai_provider.py +0 -9
  15. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/safety.py +4 -16
  16. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/scheduler.py +5 -19
  17. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/setup_wizard.py +0 -11
  18. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/tools.py +3 -10
  19. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/triton_client.py +10 -25
  20. kubrick_cli-0.1.4/kubrick_cli.egg-info/PKG-INFO +137 -0
  21. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli.egg-info/SOURCES.txt +4 -2
  22. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli.egg-info/requires.txt +2 -0
  23. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/pyproject.toml +3 -1
  24. kubrick_cli-0.1.4/tests/test_completion_detector.py +345 -0
  25. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/tests/test_config.py +47 -18
  26. kubrick_cli-0.1.4/tests/test_safety.py +294 -0
  27. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/tests/test_tool_calling.py +10 -10
  28. kubrick_cli-0.1.4/tests/test_tool_executor.py +265 -0
  29. kubrick_cli-0.1.4/tests/test_triton_client_unit.py +464 -0
  30. kubrick_cli-0.1.2/PKG-INFO +0 -86
  31. kubrick_cli-0.1.2/README.md +0 -64
  32. kubrick_cli-0.1.2/kubrick_cli.egg-info/PKG-INFO +0 -86
  33. kubrick_cli-0.1.2/tests/test_client.py +0 -74
  34. kubrick_cli-0.1.2/tests/test_triton.py +0 -127
  35. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/LICENSE +0 -0
  36. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/__init__.py +0 -0
  37. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/providers/__init__.py +0 -0
  38. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli/providers/triton_provider.py +0 -0
  39. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli.egg-info/dependency_links.txt +0 -0
  40. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli.egg-info/entry_points.txt +0 -0
  41. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/kubrick_cli.egg-info/top_level.txt +0 -0
  42. {kubrick_cli-0.1.2 → kubrick_cli-0.1.4}/setup.cfg +0 -0
@@ -0,0 +1,137 @@
1
+ Metadata-Version: 2.4
2
+ Name: kubrick-cli
3
+ Version: 0.1.4
4
+ Summary: A CLI tool for AI-assisted coding using Triton LLM backend
5
+ Author-email: Russell Land <rcland12@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/rcland12/kubrick-cli
8
+ Project-URL: Repository, https://github.com/rcland12/kubrick-cli
9
+ Project-URL: Issues, https://github.com/rcland12/kubrick-cli/issues
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: rich>=13.0.0
14
+ Requires-Dist: prompt_toolkit>=3.0.0
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
17
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
18
+ Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
19
+ Requires-Dist: black>=22.0.0; extra == "dev"
20
+ Requires-Dist: flake8>=6.0.0; extra == "dev"
21
+ Requires-Dist: build>=1.0.0; extra == "dev"
22
+ Requires-Dist: twine>=5.0.0; extra == "dev"
23
+ Dynamic: license-file
24
+
25
+ # Kubrick CLI
26
+
27
+ An AI-assisted coding CLI tool powered by your own Triton LLM backend. Like Claude Code, but self-hosted.
28
+
29
+ ## Installation
30
+
31
+ ### Local Installation
32
+
33
+ ```bash
34
+ pip install -e .
35
+ kubrick
36
+ ```
37
+
38
+ ### Docker
39
+
40
+ Available from Docker Hub or GitHub Container Registry:
41
+
42
+ ```bash
43
+ cd /path/to/your/project
44
+
45
+ # From Docker Hub
46
+ docker run --rm -it \
47
+ --network host \
48
+ -v ${HOME}:/home/kubrick \
49
+ -v ${PWD}:/workspace \
50
+ -v /etc/localtime:/etc/localtime:ro \
51
+ -v /etc/timezone:/etc/timezone:ro \
52
+ rcland12/kubrick-cli
53
+
54
+ # From GitHub Container Registry
55
+ docker run --rm -it \
56
+ --network host \
57
+ -v ${HOME}:/home/kubrick \
58
+ -v ${PWD}:/workspace \
59
+ -v /etc/localtime:/etc/localtime:ro \
60
+ -v /etc/timezone:/etc/timezone:ro \
61
+ ghcr.io/rcland12/kubrick-cli
62
+ ```
63
+
64
+ ## Quick Start
65
+
66
+ ```bash
67
+ # Basic usage
68
+ kubrick
69
+
70
+ # Custom Triton server
71
+ kubrick --triton-url my-server:8000
72
+
73
+ # Load previous conversation
74
+ kubrick --load 20240118_143022
75
+ ```
76
+
77
+ ## Requirements
78
+
79
+ - Python 3.8+
80
+ - LLM Provider (choose one):
81
+ - **Triton Inference Server** with streaming LLM model (default: `http://localhost:8000`)
82
+ - **OpenAI API** (GPT-4, GPT-3.5-turbo, etc.)
83
+ - **Anthropic API** (Claude models)
84
+
85
+ ## Documentation
86
+
87
+ - **[WIKI.md](https://github.com/rcland12/kubrick-cli/blob/master/docs/WIKI.md)** - Complete features, commands, and usage guide
88
+ - **[PROVIDERS.md](https://github.com/rcland12/kubrick-cli/blob/master/docs/PROVIDERS.md)** - Multi-provider setup (Triton, OpenAI, Anthropic)
89
+ - **[TRITON.md](https://github.com/rcland12/kubrick-cli/blob/master/docs/TRITON.md)** - Triton backend setup and requirements
90
+ - **[TESTING.md](https://github.com/rcland12/kubrick-cli/blob/master/docs/TESTING.md)** - Testing guide and CI/CD setup
91
+ - **[DOCKER.md](https://github.com/rcland12/kubrick-cli/blob/master/docs/DOCKER.md)** - Docker setup and troubleshooting
92
+
93
+ ## Configuration
94
+
95
+ Config stored at `~/.kubrick/config.json`. Override with environment variables:
96
+
97
+ ```bash
98
+ export TRITON_URL=localhost:8000
99
+ export TRITON_MODEL_NAME=llm_decoupled
100
+ ```
101
+
102
+ ## Development
103
+
104
+ ### Install Development Dependencies
105
+
106
+ ```bash
107
+ pip install -e ".[dev]"
108
+ ```
109
+
110
+ ### Run Tests
111
+
112
+ ```bash
113
+ # Run all tests
114
+ pytest
115
+
116
+ # Run with coverage
117
+ pytest --cov=kubrick_cli --cov-report=term-missing
118
+
119
+ # Run specific test file
120
+ pytest tests/test_tool_executor.py -v
121
+ ```
122
+
123
+ See [TESTING.md](https://github.com/rcland12/kubrick-cli/blob/master/docs/TESTING.md) for detailed testing documentation.
124
+
125
+ ### Code Quality
126
+
127
+ ```bash
128
+ # Format code
129
+ black kubrick_cli tests
130
+
131
+ # Check linting
132
+ flake8 kubrick_cli
133
+ ```
134
+
135
+ ## License
136
+
137
+ MIT License - See [LICENSE](LICENSE)
@@ -0,0 +1,113 @@
1
+ # Kubrick CLI
2
+
3
+ An AI-assisted coding CLI tool powered by your own Triton LLM backend. Like Claude Code, but self-hosted.
4
+
5
+ ## Installation
6
+
7
+ ### Local Installation
8
+
9
+ ```bash
10
+ pip install -e .
11
+ kubrick
12
+ ```
13
+
14
+ ### Docker
15
+
16
+ Available from Docker Hub or GitHub Container Registry:
17
+
18
+ ```bash
19
+ cd /path/to/your/project
20
+
21
+ # From Docker Hub
22
+ docker run --rm -it \
23
+ --network host \
24
+ -v ${HOME}:/home/kubrick \
25
+ -v ${PWD}:/workspace \
26
+ -v /etc/localtime:/etc/localtime:ro \
27
+ -v /etc/timezone:/etc/timezone:ro \
28
+ rcland12/kubrick-cli
29
+
30
+ # From GitHub Container Registry
31
+ docker run --rm -it \
32
+ --network host \
33
+ -v ${HOME}:/home/kubrick \
34
+ -v ${PWD}:/workspace \
35
+ -v /etc/localtime:/etc/localtime:ro \
36
+ -v /etc/timezone:/etc/timezone:ro \
37
+ ghcr.io/rcland12/kubrick-cli
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ```bash
43
+ # Basic usage
44
+ kubrick
45
+
46
+ # Custom Triton server
47
+ kubrick --triton-url my-server:8000
48
+
49
+ # Load previous conversation
50
+ kubrick --load 20240118_143022
51
+ ```
52
+
53
+ ## Requirements
54
+
55
+ - Python 3.8+
56
+ - LLM Provider (choose one):
57
+ - **Triton Inference Server** with streaming LLM model (default: `http://localhost:8000`)
58
+ - **OpenAI API** (GPT-4, GPT-3.5-turbo, etc.)
59
+ - **Anthropic API** (Claude models)
60
+
61
+ ## Documentation
62
+
63
+ - **[WIKI.md](https://github.com/rcland12/kubrick-cli/blob/master/docs/WIKI.md)** - Complete features, commands, and usage guide
64
+ - **[PROVIDERS.md](https://github.com/rcland12/kubrick-cli/blob/master/docs/PROVIDERS.md)** - Multi-provider setup (Triton, OpenAI, Anthropic)
65
+ - **[TRITON.md](https://github.com/rcland12/kubrick-cli/blob/master/docs/TRITON.md)** - Triton backend setup and requirements
66
+ - **[TESTING.md](https://github.com/rcland12/kubrick-cli/blob/master/docs/TESTING.md)** - Testing guide and CI/CD setup
67
+ - **[DOCKER.md](https://github.com/rcland12/kubrick-cli/blob/master/docs/DOCKER.md)** - Docker setup and troubleshooting
68
+
69
+ ## Configuration
70
+
71
+ Config stored at `~/.kubrick/config.json`. Override with environment variables:
72
+
73
+ ```bash
74
+ export TRITON_URL=localhost:8000
75
+ export TRITON_MODEL_NAME=llm_decoupled
76
+ ```
77
+
78
+ ## Development
79
+
80
+ ### Install Development Dependencies
81
+
82
+ ```bash
83
+ pip install -e ".[dev]"
84
+ ```
85
+
86
+ ### Run Tests
87
+
88
+ ```bash
89
+ # Run all tests
90
+ pytest
91
+
92
+ # Run with coverage
93
+ pytest --cov=kubrick_cli --cov-report=term-missing
94
+
95
+ # Run specific test file
96
+ pytest tests/test_tool_executor.py -v
97
+ ```
98
+
99
+ See [TESTING.md](https://github.com/rcland12/kubrick-cli/blob/master/docs/TESTING.md) for detailed testing documentation.
100
+
101
+ ### Code Quality
102
+
103
+ ```bash
104
+ # Format code
105
+ black kubrick_cli tests
106
+
107
+ # Check linting
108
+ flake8 kubrick_cli
109
+ ```
110
+
111
+ ## License
112
+
113
+ MIT License - See [LICENSE](LICENSE)
@@ -1,19 +1,17 @@
1
1
  """Multi-step agentic execution loop with completion detection."""
2
2
 
3
3
  import re
4
- from typing import Dict, Iterator, List, Optional, Tuple
4
+ from typing import Dict, List, Tuple
5
5
 
6
6
  from rich.console import Console
7
7
 
8
8
  console = Console()
9
9
 
10
- # Import display manager (will be None if not available)
11
10
  try:
12
11
  from .display import DisplayManager
13
12
  except ImportError:
14
13
  DisplayManager = None
15
14
 
16
- # Import scheduler (will be None if not available)
17
15
  try:
18
16
  from .scheduler import ToolScheduler
19
17
  except ImportError:
@@ -23,7 +21,6 @@ except ImportError:
23
21
  class CompletionDetector:
24
22
  """Detects when an agent has completed its task."""
25
23
 
26
- # Explicit completion markers the agent can use
27
24
  COMPLETION_MARKERS = [
28
25
  "TASK_COMPLETE",
29
26
  "PLAN_COMPLETE",
@@ -50,22 +47,17 @@ class CompletionDetector:
50
47
  Returns:
51
48
  Tuple of (is_complete, reason)
52
49
  """
53
- # Check for explicit completion markers
54
50
  for marker in CompletionDetector.COMPLETION_MARKERS:
55
51
  if marker in response_text:
56
52
  return True, f"explicit_marker:{marker}"
57
53
 
58
- # Max iterations reached (fallback safety)
59
54
  if iteration >= max_iterations:
60
55
  return True, "max_iterations_reached"
61
56
 
62
- # If no tool calls and response looks conclusive
63
57
  if not has_tool_calls:
64
- # Check if response appears to be a final summary/conclusion
65
58
  if CompletionDetector._looks_conclusive(response_text):
66
59
  return True, "conclusive_response"
67
60
 
68
- # Otherwise, continue
69
61
  return False, "continuing"
70
62
 
71
63
  @staticmethod
@@ -78,7 +70,6 @@ class CompletionDetector:
78
70
  """
79
71
  text_lower = text.lower()
80
72
 
81
- # Look for summary/conclusion indicators
82
73
  conclusive_patterns = [
83
74
  r"\b(done|completed|finished|ready)\b",
84
75
  r"\b(successfully|all set|good to go)\b",
@@ -163,7 +154,6 @@ class AgentLoop:
163
154
  f"\n[dim]→ Agent iteration {iteration}/{self.max_iterations}[/dim]"
164
155
  )
165
156
 
166
- # Get LLM response
167
157
  console.print("[bold cyan]Assistant:[/bold cyan]")
168
158
  chunks = []
169
159
 
@@ -185,20 +175,15 @@ class AgentLoop:
185
175
  "tool_calls": total_tool_calls,
186
176
  }
187
177
 
188
- # Get full response
189
178
  response_text = "".join(chunks)
190
179
 
191
- # Add to conversation
192
180
  messages.append({"role": "assistant", "content": response_text})
193
181
 
194
- # Display with custom callback if provided
195
182
  if display_callback:
196
183
  display_callback(response_text)
197
184
 
198
- # Parse tool calls
199
185
  tool_calls = tool_parser(response_text)
200
186
 
201
- # Check completion
202
187
  is_complete, reason = CompletionDetector.is_complete(
203
188
  response_text=response_text,
204
189
  has_tool_calls=len(tool_calls) > 0,
@@ -215,9 +200,7 @@ class AgentLoop:
215
200
  "tool_calls": total_tool_calls,
216
201
  }
217
202
 
218
- # Execute tool calls if any
219
203
  if tool_calls:
220
- # Enforce max tools per turn
221
204
  if len(tool_calls) > self.max_tools_per_turn:
222
205
  console.print(
223
206
  f"[yellow]⚠ Too many tool calls ({len(tool_calls)}), "
@@ -229,44 +212,32 @@ class AgentLoop:
229
212
  f"\n[yellow]Executing {len(tool_calls)} tool(s)...[/yellow]\n"
230
213
  )
231
214
 
232
- # Execute tools (with or without scheduler)
233
215
  if self.tool_scheduler and len(tool_calls) > 1:
234
- # Use scheduler for parallel execution
235
- execution_results = self.tool_scheduler.execute_tools(
236
- tool_calls
237
- )
216
+ execution_results = self.tool_scheduler.execute_tools(tool_calls)
238
217
  else:
239
- # Execute sequentially
240
218
  execution_results = [
241
219
  self.tool_executor.execute(tool_name, params)
242
220
  for tool_name, params in tool_calls
243
221
  ]
244
222
 
245
- # Display and collect results
246
223
  tool_results = []
247
224
  for (tool_name, parameters), result in zip(
248
225
  tool_calls, execution_results
249
226
  ):
250
- # Display tool call and result
251
227
  if self.display_manager:
252
- self.display_manager.display_tool_call(
253
- tool_name, parameters
254
- )
228
+ self.display_manager.display_tool_call(tool_name, parameters)
255
229
  self.display_manager.display_tool_result(
256
230
  tool_name, result, result["success"]
257
231
  )
258
232
  else:
259
233
  console.print(f"[cyan]→ Called {tool_name}[/cyan]")
260
234
  if result["success"]:
261
- console.print(
262
- f"[green]✓ {tool_name} succeeded[/green]"
263
- )
235
+ console.print(f"[green]✓ {tool_name} succeeded[/green]")
264
236
  else:
265
237
  console.print(
266
238
  f"[red]✗ {tool_name} failed: {result['error']}[/red]"
267
239
  )
268
240
 
269
- # Add to results
270
241
  if result["success"]:
271
242
  tool_results.append(
272
243
  f"Tool: {tool_name}\nResult: {result['result']}"
@@ -278,7 +249,6 @@ class AgentLoop:
278
249
 
279
250
  total_tool_calls += 1
280
251
 
281
- # Add tool results to conversation
282
252
  tool_results_text = "\n\n".join(tool_results)
283
253
  messages.append(
284
254
  {
@@ -287,15 +257,12 @@ class AgentLoop:
287
257
  }
288
258
  )
289
259
 
290
- # Continue to next iteration
291
260
  continue
292
261
 
293
- # If no tool calls and not complete, something might be wrong
294
262
  console.print(
295
263
  "[yellow]⚠ No tool calls and task not marked complete. Continuing...[/yellow]"
296
264
  )
297
265
 
298
- # Max iterations reached
299
266
  console.print(
300
267
  f"\n[yellow]⚠ Max iterations ({self.max_iterations}) reached[/yellow]"
301
268
  )
@@ -64,7 +64,6 @@ class TaskClassifier:
64
64
  Returns:
65
65
  TaskClassification object with detailed classification
66
66
  """
67
- # Build classification prompt
68
67
  classification_messages = [
69
68
  {
70
69
  "role": "system",
@@ -146,12 +145,10 @@ Respond with ONLY the JSON object, no other text.""",
146
145
  ]
147
146
 
148
147
  try:
149
- # Get classification from LLM (non-streaming for speed)
150
148
  response = self.llm_client.generate(
151
149
  classification_messages, stream_options={}
152
150
  )
153
151
 
154
- # Parse JSON response
155
152
  json_start = response.find("{")
156
153
  json_end = response.rfind("}") + 1
157
154
 
@@ -175,7 +172,6 @@ Respond with ONLY the JSON object, no other text.""",
175
172
  requires_tools=requires_tools,
176
173
  )
177
174
 
178
- # Fallback: default to SIMPLE if parsing fails
179
175
  console.print(
180
176
  "[yellow]⚠ Classification parsing failed, defaulting to SIMPLE[/yellow]"
181
177
  )
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python3
2
1
  """Configuration management for Kubrick CLI."""
3
2
 
4
3
  import json
@@ -23,10 +22,8 @@ class KubrickConfig:
23
22
  self.config_file = self.kubrick_dir / "config.json"
24
23
  self.conversations_dir = self.kubrick_dir / "conversations"
25
24
 
26
- # Ensure directories exist
27
25
  self._ensure_directories()
28
26
 
29
- # Load or create config (with optional setup wizard)
30
27
  self.config = self._load_config(skip_wizard=skip_wizard)
31
28
 
32
29
  def _ensure_directories(self):
@@ -49,29 +46,24 @@ class KubrickConfig:
49
46
  with open(self.config_file, "r") as f:
50
47
  loaded_config = json.load(f)
51
48
 
52
- # Merge with defaults to ensure all keys exist
53
49
  default_config = self._get_default_config()
54
50
  default_config.update(loaded_config)
55
51
  return default_config
56
52
 
57
53
  except (json.JSONDecodeError, IOError):
58
- # If config is corrupted, start fresh
59
54
  return self._get_default_config()
60
55
  else:
61
- # First time setup - run wizard unless skipped
62
56
  if not skip_wizard:
63
57
  from .setup_wizard import SetupWizard
64
58
 
65
59
  wizard_config = SetupWizard.run()
66
60
 
67
- # Merge wizard config with defaults
68
61
  config = self._get_default_config()
69
62
  config.update(wizard_config)
70
63
 
71
64
  self._save_config(config)
72
65
  return config
73
66
  else:
74
- # Create default config without wizard
75
67
  config = self._get_default_config()
76
68
  self._save_config(config)
77
69
  return config
@@ -105,7 +97,7 @@ class KubrickConfig:
105
97
  "tool_timeout_seconds": 30,
106
98
  "max_file_size_mb": 10,
107
99
  # Display settings
108
- "display_mode": "natural", # natural, json, verbose
100
+ "display_mode": "natural",
109
101
  "show_tool_results": True,
110
102
  "show_progress": True,
111
103
  # Task classification settings
@@ -156,20 +148,30 @@ class KubrickConfig:
156
148
  with open(conversation_file, "w") as f:
157
149
  json.dump(data, f, indent=2)
158
150
 
159
- # Clean up old conversations if we exceed max
160
151
  self._cleanup_old_conversations()
161
152
 
162
153
  def load_conversation(self, conversation_id: str) -> Optional[Dict]:
163
154
  """
164
155
  Load a conversation from disk.
165
156
 
157
+ Supports two modes:
158
+ 1. By ID: Loads from ~/.kubrick/conversations/<id>.json
159
+ 2. By path: Loads from absolute or relative file path
160
+
166
161
  Args:
167
- conversation_id: Unique identifier for the conversation
162
+ conversation_id: Conversation ID or file path
168
163
 
169
164
  Returns:
170
165
  Dictionary with 'id', 'messages', and 'metadata', or None if not found
171
166
  """
172
- conversation_file = self.conversations_dir / f"{conversation_id}.json"
167
+ if (
168
+ "/" in conversation_id
169
+ or "\\" in conversation_id
170
+ or conversation_id.endswith(".json")
171
+ ):
172
+ conversation_file = Path(conversation_id).expanduser().resolve()
173
+ else:
174
+ conversation_file = self.conversations_dir / f"{conversation_id}.json"
173
175
 
174
176
  if not conversation_file.exists():
175
177
  return None
@@ -208,7 +210,6 @@ class KubrickConfig:
208
210
  except (json.JSONDecodeError, IOError):
209
211
  continue
210
212
 
211
- # Sort by modification time (newest first)
212
213
  conversations.sort(key=lambda x: x["modified"], reverse=True)
213
214
 
214
215
  if limit:
@@ -240,9 +241,7 @@ class KubrickConfig:
240
241
  conversations = list(self.conversations_dir.glob("*.json"))
241
242
 
242
243
  if len(conversations) > max_conversations:
243
- # Sort by modification time (oldest first)
244
244
  conversations.sort(key=lambda x: x.stat().st_mtime)
245
245
 
246
- # Delete oldest conversations
247
246
  for conv_file in conversations[: len(conversations) - max_conversations]:
248
247
  conv_file.unlink()
@@ -65,16 +65,12 @@ class DisplayManager:
65
65
  elif self.display_mode in ("json", "verbose"):
66
66
  self._display_json_result(tool_name, result, success)
67
67
 
68
- def _display_natural_tool_call(
69
- self, tool_name: str, parameters: Dict[str, Any]
70
- ):
68
+ def _display_natural_tool_call(self, tool_name: str, parameters: Dict[str, Any]):
71
69
  """Display tool call in natural language."""
72
70
  description = self._get_natural_description(tool_name, parameters)
73
71
  console.print(f"[cyan]→ {description}[/cyan]")
74
72
 
75
- def _display_json_tool_call(
76
- self, tool_name: str, parameters: Dict[str, Any]
77
- ):
73
+ def _display_json_tool_call(self, tool_name: str, parameters: Dict[str, Any]):
78
74
  """Display tool call as JSON panel."""
79
75
  tool_data = {"tool": tool_name, "parameters": parameters}
80
76
  json_str = json.dumps(tool_data, indent=2)
@@ -86,15 +82,12 @@ class DisplayManager:
86
82
  ):
87
83
  """Display result in natural language."""
88
84
  if success:
89
- # Extract key information from result
90
85
  result_text = result.get("result", "")
91
86
 
92
- # Truncate long results for display
93
87
  if len(result_text) > 200:
94
88
  preview = result_text[:200] + "..."
95
- console.print(
96
- f"[green]✓ {tool_name} succeeded[/green] [dim](output truncated)[/dim]"
97
- )
89
+ console.print(f"[green]✓ {tool_name} succeeded[/green]")
90
+ console.print(f"[dim]{preview}[/dim]")
98
91
  else:
99
92
  console.print(f"[green]✓ {tool_name} succeeded[/green]")
100
93
  else:
@@ -131,9 +124,7 @@ class DisplayManager:
131
124
  elif tool_name == "write_file":
132
125
  file_path = parameters.get("file_path", "unknown")
133
126
  content_length = len(parameters.get("content", ""))
134
- return (
135
- f"Writing {content_length} characters to {file_path}"
136
- )
127
+ return f"Writing {content_length} characters to {file_path}"
137
128
 
138
129
  elif tool_name == "edit_file":
139
130
  file_path = parameters.get("file_path", "unknown")
@@ -151,7 +142,6 @@ class DisplayManager:
151
142
 
152
143
  elif tool_name == "run_bash":
153
144
  command = parameters.get("command", "")
154
- # Truncate long commands
155
145
  if len(command) > 60:
156
146
  command = command[:60] + "..."
157
147
  return f"Running bash command: {command}"
@@ -161,5 +151,4 @@ class DisplayManager:
161
151
  return f"Creating directory {path}"
162
152
 
163
153
  else:
164
- # Fallback for unknown tools
165
154
  return f"Calling {tool_name}"
@@ -30,7 +30,6 @@ class ExecutionStrategy:
30
30
  - Quality (best models for complex tasks)
31
31
  """
32
32
 
33
- # Model tiers by provider
34
33
  MODEL_TIERS = {
35
34
  "openai": {
36
35
  "fast": "gpt-3.5-turbo",
@@ -38,13 +37,12 @@ class ExecutionStrategy:
38
37
  "best": "gpt-4",
39
38
  },
40
39
  "anthropic": {
41
- "fast": "claude-haiku-4-5-20251001", # 4-5x faster, 1/3 cost
42
- "balanced": "claude-sonnet-4-5-20250929", # Claude Sonnet 4.5 (best balance, workhorse)
43
- "best": "claude-opus-4-1-20250805", # Claude Opus 4.1 (most capable)
40
+ "fast": "claude-haiku-4-5-20251001",
41
+ "balanced": "claude-sonnet-4-5-20250929",
42
+ "best": "claude-opus-4-1-20250805",
44
43
  },
45
44
  "triton": {
46
- # Triton uses same model for all tiers
47
- "fast": None, # Use configured model
45
+ "fast": None,
48
46
  "balanced": None,
49
47
  "best": None,
50
48
  },