kash-shell 0.3.35__py3-none-any.whl → 0.3.37__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.
- kash/exec/llm_transforms.py +4 -0
- kash/file_storage/file_store.py +4 -0
- kash/llm_utils/llm_completion.py +115 -19
- kash/llm_utils/llms.py +8 -7
- kash/local_server/local_server_routes.py +2 -2
- kash/media_base/transcription_deepgram.py +18 -24
- kash/model/actions_model.py +7 -3
- kash/model/assistant_response_model.py +2 -2
- kash/model/items_model.py +8 -1
- kash/model/params_model.py +4 -4
- kash/shell/file_icons/nerd_icons.py +2 -2
- kash/shell/output/kerm_codes.py +5 -5
- kash/utils/api_utils/cache_requests_limited.py +6 -6
- kash/utils/file_formats/chat_format.py +2 -2
- kash/utils/file_utils/file_sort_filter.py +4 -4
- kash/web_gen/templates/youtube_webpage.html.jinja +3 -2
- {kash_shell-0.3.35.dist-info → kash_shell-0.3.37.dist-info}/METADATA +1 -1
- {kash_shell-0.3.35.dist-info → kash_shell-0.3.37.dist-info}/RECORD +21 -21
- {kash_shell-0.3.35.dist-info → kash_shell-0.3.37.dist-info}/WHEEL +1 -1
- {kash_shell-0.3.35.dist-info → kash_shell-0.3.37.dist-info}/entry_points.txt +0 -0
- {kash_shell-0.3.35.dist-info → kash_shell-0.3.37.dist-info}/licenses/LICENSE +0 -0
kash/exec/llm_transforms.py
CHANGED
|
@@ -29,6 +29,7 @@ def windowed_llm_transform(
|
|
|
29
29
|
windowing: WindowSettings | None,
|
|
30
30
|
diff_filter: DiffFilter | None = None,
|
|
31
31
|
check_no_results: bool = True,
|
|
32
|
+
enable_web_search: bool = False,
|
|
32
33
|
) -> TextDoc:
|
|
33
34
|
def doc_transform(input_doc: TextDoc) -> TextDoc:
|
|
34
35
|
return TextDoc.from_text(
|
|
@@ -41,6 +42,7 @@ def windowed_llm_transform(
|
|
|
41
42
|
input=input_doc.reassemble(),
|
|
42
43
|
body_template=template,
|
|
43
44
|
check_no_results=check_no_results,
|
|
45
|
+
enable_web_search=enable_web_search,
|
|
44
46
|
).content
|
|
45
47
|
)
|
|
46
48
|
)
|
|
@@ -67,6 +69,7 @@ def llm_transform_str(options: LLMOptions, input_str: str, check_no_results: boo
|
|
|
67
69
|
input_str,
|
|
68
70
|
options.windowing,
|
|
69
71
|
diff_filter=options.diff_filter,
|
|
72
|
+
enable_web_search=options.enable_web_search,
|
|
70
73
|
).reassemble()
|
|
71
74
|
else:
|
|
72
75
|
log.info(
|
|
@@ -81,6 +84,7 @@ def llm_transform_str(options: LLMOptions, input_str: str, check_no_results: boo
|
|
|
81
84
|
body_template=options.body_template,
|
|
82
85
|
input=input_str,
|
|
83
86
|
check_no_results=check_no_results,
|
|
87
|
+
enable_web_search=options.enable_web_search,
|
|
84
88
|
).content
|
|
85
89
|
|
|
86
90
|
return result_str
|
kash/file_storage/file_store.py
CHANGED
|
@@ -485,6 +485,9 @@ class FileStore(Workspace):
|
|
|
485
485
|
If `with_sidematter` is true, will copy any sidematter files (metadata/assets) to
|
|
486
486
|
the destination.
|
|
487
487
|
"""
|
|
488
|
+
# TODO: Make sure importing a text item that already has
|
|
489
|
+
# frontmatter doesn't accidentally duplicate the frontmatter
|
|
490
|
+
|
|
488
491
|
from kash.file_storage.item_file_format import read_item
|
|
489
492
|
from kash.web_content.canon_url import canonicalize_url
|
|
490
493
|
|
|
@@ -531,6 +534,7 @@ class FileStore(Workspace):
|
|
|
531
534
|
# This will read the file with or without frontmatter.
|
|
532
535
|
# We are importing so we want to drop the external path so we save the body.
|
|
533
536
|
item = read_item(path, self.base_dir)
|
|
537
|
+
log.info("Imported text item: %s", item)
|
|
534
538
|
item.external_path = None
|
|
535
539
|
|
|
536
540
|
if item.type and as_type and item.type != as_type:
|
kash/llm_utils/llm_completion.py
CHANGED
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import time
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from typing import TYPE_CHECKING, cast
|
|
5
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
6
6
|
|
|
7
7
|
from flowmark import Wrap, fill_text
|
|
8
8
|
from funlog import format_duration, log_calls
|
|
@@ -51,6 +51,7 @@ class LLMCompletionResult:
|
|
|
51
51
|
message: LiteLLMMessage
|
|
52
52
|
content: str
|
|
53
53
|
citations: CitationList | None
|
|
54
|
+
tool_calls: list[dict[str, Any]] | None = None
|
|
54
55
|
|
|
55
56
|
@property
|
|
56
57
|
def content_with_citations(self) -> str:
|
|
@@ -59,40 +60,111 @@ class LLMCompletionResult:
|
|
|
59
60
|
content = content + "\n\n" + self.citations.as_markdown_footnotes()
|
|
60
61
|
return content
|
|
61
62
|
|
|
63
|
+
@property
|
|
64
|
+
def has_tool_calls(self) -> bool:
|
|
65
|
+
"""Check if the response contains tool calls."""
|
|
66
|
+
return bool(self.tool_calls)
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def tool_call_names(self) -> list[str]:
|
|
70
|
+
"""Get list of tool names that were called."""
|
|
71
|
+
if not self.tool_calls:
|
|
72
|
+
return []
|
|
73
|
+
names = []
|
|
74
|
+
for call in self.tool_calls:
|
|
75
|
+
# Handle both LiteLLM objects and dict representations
|
|
76
|
+
if hasattr(call, "function") and hasattr(getattr(call, "function", None), "name"):
|
|
77
|
+
# LiteLLM object format
|
|
78
|
+
names.append(f"{call.function.name}()") # pyright: ignore[reportAttributeAccessIssue]
|
|
79
|
+
elif isinstance(call, dict) and call.get("function", {}).get("name"):
|
|
80
|
+
# Dict format
|
|
81
|
+
names.append(f"{call['function']['name']}()")
|
|
82
|
+
else:
|
|
83
|
+
names.append(str(call))
|
|
84
|
+
return names
|
|
85
|
+
|
|
62
86
|
|
|
63
87
|
@log_calls(level="info")
|
|
64
88
|
def llm_completion(
|
|
65
89
|
model: LLMName,
|
|
66
90
|
messages: list[dict[str, str]],
|
|
67
91
|
save_objects: bool = True,
|
|
68
|
-
response_format: dict | type[BaseModel] | None = None,
|
|
92
|
+
response_format: dict[str, Any] | type[BaseModel] | None = None,
|
|
93
|
+
tools: list[dict[str, Any]] | None = None,
|
|
94
|
+
enable_web_search: bool = False,
|
|
69
95
|
**kwargs,
|
|
70
96
|
) -> LLMCompletionResult:
|
|
71
97
|
"""
|
|
72
98
|
Perform an LLM completion with LiteLLM.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
model: The LLM model to use
|
|
102
|
+
messages: Chat messages
|
|
103
|
+
save_objects: Whether to save chat history
|
|
104
|
+
response_format: Response format specification
|
|
105
|
+
tools: List of tools available for function calling (e.g., web_search)
|
|
106
|
+
enable_web_search: If True, automatically add web search tools for the model
|
|
107
|
+
**kwargs: Additional LiteLLM parameters
|
|
73
108
|
"""
|
|
74
|
-
import litellm
|
|
75
109
|
from litellm.types.utils import Choices, ModelResponse
|
|
76
110
|
|
|
77
111
|
init_litellm()
|
|
78
112
|
|
|
113
|
+
# Prepare completion parameters
|
|
114
|
+
completion_params = {
|
|
115
|
+
"model": model.litellm_name,
|
|
116
|
+
"messages": messages,
|
|
117
|
+
**kwargs,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
# Auto-enable web search if requested
|
|
121
|
+
if enable_web_search:
|
|
122
|
+
import litellm
|
|
123
|
+
|
|
124
|
+
if litellm.supports_web_search(model=model.litellm_name):
|
|
125
|
+
log.message("Enabling web search for model %s", model.litellm_name)
|
|
126
|
+
completion_params["web_search_options"] = {"search_context_size": "medium"}
|
|
127
|
+
else:
|
|
128
|
+
log.warning("Web search requested but not supported by model %s", model.litellm_name)
|
|
129
|
+
|
|
79
130
|
chat_history = ChatHistory.from_dicts(messages)
|
|
131
|
+
|
|
132
|
+
# Enhanced logging to detect tool use
|
|
133
|
+
tools_info = f", {len(tools)} tools" if tools else ", no tools"
|
|
80
134
|
log.info(
|
|
81
|
-
"Calling LLM completion from %s on %s, response_format=%s",
|
|
135
|
+
"Calling LLM completion from %s on %s, response_format=%s%s",
|
|
82
136
|
model.litellm_name,
|
|
83
137
|
chat_history.size_summary(),
|
|
84
138
|
response_format,
|
|
139
|
+
tools_info,
|
|
85
140
|
)
|
|
86
141
|
|
|
142
|
+
if tools:
|
|
143
|
+
tool_names = []
|
|
144
|
+
for tool in tools:
|
|
145
|
+
if tool.get("type") == "function":
|
|
146
|
+
tool_names.append(tool.get("function", {}).get("name", "unknown"))
|
|
147
|
+
elif tool.get("type") == "native_web_search":
|
|
148
|
+
tool_names.append("native_web_search")
|
|
149
|
+
else:
|
|
150
|
+
tool_names.append(tool.get("type", "unknown"))
|
|
151
|
+
|
|
152
|
+
log.message("Tools enabled: %s", tool_names)
|
|
153
|
+
|
|
87
154
|
start_time = time.time()
|
|
155
|
+
|
|
156
|
+
if response_format:
|
|
157
|
+
completion_params["response_format"] = response_format
|
|
158
|
+
|
|
159
|
+
if tools:
|
|
160
|
+
completion_params["tools"] = tools
|
|
161
|
+
log.info("Enabling function calling with %d tools", len(tools))
|
|
162
|
+
|
|
163
|
+
import litellm
|
|
164
|
+
|
|
88
165
|
llm_output = cast(
|
|
89
166
|
ModelResponse,
|
|
90
|
-
litellm.completion(
|
|
91
|
-
model.litellm_name,
|
|
92
|
-
messages=messages,
|
|
93
|
-
response_format=response_format,
|
|
94
|
-
**kwargs,
|
|
95
|
-
), # pyright: ignore
|
|
167
|
+
litellm.completion(**completion_params), # pyright: ignore
|
|
96
168
|
)
|
|
97
169
|
elapsed = time.time() - start_time
|
|
98
170
|
|
|
@@ -100,23 +172,47 @@ def llm_completion(
|
|
|
100
172
|
|
|
101
173
|
message = choices.message
|
|
102
174
|
|
|
175
|
+
# Extract tool calls from the response
|
|
176
|
+
tool_calls = getattr(message, "tool_calls", None)
|
|
177
|
+
tool_calls_list = list(tool_calls) if tool_calls else None
|
|
178
|
+
|
|
103
179
|
# Just sanity checking and logging.
|
|
104
180
|
content = choices.message.content
|
|
105
181
|
if not content or not isinstance(content, str):
|
|
106
182
|
raise ApiResultError(f"LLM completion failed: {model.litellm_name}: {llm_output}")
|
|
107
183
|
|
|
184
|
+
# Create the result object with tool calls
|
|
185
|
+
citations = llm_output.get("citations", None)
|
|
186
|
+
result = LLMCompletionResult(
|
|
187
|
+
message=message,
|
|
188
|
+
content=content,
|
|
189
|
+
citations=CitationList(citations=citations) if citations else None,
|
|
190
|
+
tool_calls=tool_calls_list,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# Log tool calls if present
|
|
194
|
+
if result.has_tool_calls:
|
|
195
|
+
tool_count = len(result.tool_calls or [])
|
|
196
|
+
log.message("LLM executed %d function calls: %s", tool_count, result.tool_call_names)
|
|
197
|
+
log.message(
|
|
198
|
+
"⚠️ Function calls require implementation - LLM requested tools but no handlers are implemented"
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
# Performance logging
|
|
108
202
|
total_input_len = sum(len(m["content"]) for m in messages)
|
|
109
203
|
speed = len(content) / elapsed
|
|
204
|
+
tool_count = len(result.tool_calls or []) if result.has_tool_calls else 0
|
|
205
|
+
tool_info = f", {tool_count} tool calls" if result.has_tool_calls else ""
|
|
110
206
|
log.info(
|
|
111
207
|
f"{EMOJI_TIMING} LLM completion from {model.litellm_name} in {format_duration(elapsed)}: "
|
|
112
208
|
f"input {total_input_len} chars in {len(messages)} messages, output {len(content)} chars "
|
|
113
|
-
f"({speed:.0f} char/s)"
|
|
209
|
+
f"({speed:.0f} char/s){tool_info}"
|
|
114
210
|
)
|
|
115
211
|
|
|
116
|
-
citations = llm_output.get("citations", None)
|
|
117
|
-
|
|
118
212
|
if save_objects:
|
|
119
213
|
metadata = {"citations": citations} if citations else {}
|
|
214
|
+
if result.has_tool_calls:
|
|
215
|
+
metadata["tool_calls"] = len(result.tool_calls or [])
|
|
120
216
|
chat_history.messages.append(
|
|
121
217
|
ChatMessage(role=ChatRole.assistant, content=content, metadata=metadata)
|
|
122
218
|
)
|
|
@@ -128,11 +224,7 @@ def llm_completion(
|
|
|
128
224
|
file_ext="yml",
|
|
129
225
|
)
|
|
130
226
|
|
|
131
|
-
return
|
|
132
|
-
message=message,
|
|
133
|
-
content=content,
|
|
134
|
-
citations=CitationList(citations=citations) if citations else None,
|
|
135
|
-
)
|
|
227
|
+
return result
|
|
136
228
|
|
|
137
229
|
|
|
138
230
|
def llm_template_completion(
|
|
@@ -143,7 +235,9 @@ def llm_template_completion(
|
|
|
143
235
|
previous_messages: list[dict[str, str]] | None = None,
|
|
144
236
|
save_objects: bool = True,
|
|
145
237
|
check_no_results: bool = True,
|
|
146
|
-
response_format: dict | type[BaseModel] | None = None,
|
|
238
|
+
response_format: dict[str, Any] | type[BaseModel] | None = None,
|
|
239
|
+
tools: list[dict[str, Any]] | None = None,
|
|
240
|
+
enable_web_search: bool = False,
|
|
147
241
|
**kwargs,
|
|
148
242
|
) -> LLMCompletionResult:
|
|
149
243
|
"""
|
|
@@ -169,6 +263,8 @@ def llm_template_completion(
|
|
|
169
263
|
],
|
|
170
264
|
save_objects=save_objects,
|
|
171
265
|
response_format=response_format,
|
|
266
|
+
tools=tools,
|
|
267
|
+
enable_web_search=enable_web_search,
|
|
172
268
|
**kwargs,
|
|
173
269
|
)
|
|
174
270
|
|
kash/llm_utils/llms.py
CHANGED
|
@@ -28,22 +28,23 @@ class LLM(LLMName, Enum):
|
|
|
28
28
|
gpt_4_1 = LLMName("gpt-4.1")
|
|
29
29
|
gpt_4o = LLMName("gpt-4o")
|
|
30
30
|
gpt_4o_mini = LLMName("gpt-4o-mini")
|
|
31
|
+
gpt_4o_search_preview = LLMName("gpt-4o-search-preview")
|
|
31
32
|
gpt_4 = LLMName("gpt-4")
|
|
32
33
|
gpt_4_1_mini = LLMName("gpt-4.1-mini")
|
|
33
34
|
gpt_4_1_nano = LLMName("gpt-4.1-nano")
|
|
34
35
|
|
|
35
|
-
# https://docs.
|
|
36
|
+
# https://docs.claude.com/en/docs/about-claude/models
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
claude_sonnet_4_5 = LLMName("claude-sonnet-4-5-20250929")
|
|
39
|
+
claude_haiku_4_5 = LLMName("claude-haiku-4-5-20251001")
|
|
40
|
+
claude_opus_4_1 = LLMName("claude-opus-4-1-20250805")
|
|
41
|
+
claude_sonnet_4 = LLMName("claude-sonnet-4-20250514")
|
|
42
|
+
claude_opus_4 = LLMName("claude-opus-4-20250514")
|
|
42
43
|
|
|
43
44
|
# https://ai.google.dev/gemini-api/docs/models
|
|
44
45
|
gemini_2_5_pro = LLMName("gemini/gemini-2.5-pro")
|
|
45
46
|
gemini_2_5_flash = LLMName("gemini/gemini-2.5-flash")
|
|
46
|
-
gemini_2_5_flash_lite = LLMName("gemini-2.5-flash-lite
|
|
47
|
+
gemini_2_5_flash_lite = LLMName("gemini/gemini-2.5-flash-lite")
|
|
47
48
|
|
|
48
49
|
# https://docs.x.ai/docs/models
|
|
49
50
|
xai_grok_3 = LLMName("xai/grok-3")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from enum import
|
|
1
|
+
from enum import StrEnum
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from urllib.parse import urlencode
|
|
4
4
|
|
|
@@ -55,7 +55,7 @@ def format_local_url(route_path: str, **params: str | None) -> str:
|
|
|
55
55
|
return url
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
class Route(
|
|
58
|
+
class Route(StrEnum):
|
|
59
59
|
file_view = "/file/view"
|
|
60
60
|
item_view = "/item/view"
|
|
61
61
|
explain = "/explain"
|
|
@@ -5,34 +5,28 @@ from pathlib import Path
|
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
7
|
from clideps.env_vars.dotenv_utils import load_dotenv_paths
|
|
8
|
-
from httpx import Timeout
|
|
9
8
|
|
|
10
9
|
from kash.config.logger import CustomLogger, get_logger
|
|
11
10
|
from kash.config.settings import global_settings
|
|
12
11
|
from kash.media_base.transcription_format import SpeakerSegment, format_speaker_segments
|
|
13
|
-
from kash.utils.errors import
|
|
12
|
+
from kash.utils.errors import ContentError
|
|
14
13
|
|
|
15
14
|
if TYPE_CHECKING:
|
|
16
|
-
from deepgram import
|
|
15
|
+
from deepgram.types.listen_v1accepted_response import ListenV1AcceptedResponse
|
|
16
|
+
from deepgram.types.listen_v1response import ListenV1Response
|
|
17
17
|
|
|
18
18
|
log: CustomLogger = get_logger(__name__)
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def deepgram_transcribe_raw(
|
|
22
22
|
audio_file_path: Path, language: str | None = None
|
|
23
|
-
) ->
|
|
23
|
+
) -> ListenV1Response | ListenV1AcceptedResponse:
|
|
24
24
|
"""
|
|
25
25
|
Transcribe an audio file using Deepgram and return the raw response.
|
|
26
26
|
"""
|
|
27
27
|
# Slow import, do lazily.
|
|
28
|
-
from deepgram import
|
|
29
|
-
|
|
30
|
-
DeepgramClient,
|
|
31
|
-
FileSource,
|
|
32
|
-
ListenRESTClient,
|
|
33
|
-
PrerecordedOptions,
|
|
34
|
-
PrerecordedResponse,
|
|
35
|
-
)
|
|
28
|
+
from deepgram import DeepgramClient
|
|
29
|
+
from deepgram.core.request_options import RequestOptions
|
|
36
30
|
|
|
37
31
|
size = getsize(audio_file_path)
|
|
38
32
|
log.info(
|
|
@@ -40,21 +34,19 @@ def deepgram_transcribe_raw(
|
|
|
40
34
|
)
|
|
41
35
|
|
|
42
36
|
load_dotenv_paths(True, True, global_settings().system_config_dir)
|
|
43
|
-
deepgram = DeepgramClient(
|
|
37
|
+
deepgram = DeepgramClient()
|
|
44
38
|
|
|
45
39
|
with open(audio_file_path, "rb") as audio_file:
|
|
46
40
|
buffer_data = audio_file.read()
|
|
47
41
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if not isinstance(response, PrerecordedResponse):
|
|
57
|
-
raise ApiError("Deepgram returned an unexpected response type")
|
|
42
|
+
response = deepgram.listen.v1.media.transcribe_file(
|
|
43
|
+
request=buffer_data,
|
|
44
|
+
model="nova-2",
|
|
45
|
+
smart_format=True,
|
|
46
|
+
diarize=True,
|
|
47
|
+
language=language,
|
|
48
|
+
request_options=RequestOptions(timeout_in_seconds=500),
|
|
49
|
+
)
|
|
58
50
|
|
|
59
51
|
return response
|
|
60
52
|
|
|
@@ -64,7 +56,9 @@ def deepgram_transcribe_audio(audio_file_path: Path, language: str | None = None
|
|
|
64
56
|
|
|
65
57
|
log.save_object("Deepgram response", None, response)
|
|
66
58
|
|
|
67
|
-
|
|
59
|
+
# Convert Pydantic model to dict for processing.
|
|
60
|
+
response_dict = response.model_dump()
|
|
61
|
+
diarized_segments = _deepgram_diarized_segments(response_dict)
|
|
68
62
|
log.debug("Diarized response: %s", diarized_segments)
|
|
69
63
|
|
|
70
64
|
if not diarized_segments:
|
kash/model/actions_model.py
CHANGED
|
@@ -171,6 +171,7 @@ class LLMOptions:
|
|
|
171
171
|
body_template: MessageTemplate = MessageTemplate("{body}")
|
|
172
172
|
windowing: WindowSettings = WINDOW_NONE
|
|
173
173
|
diff_filter: DiffFilter | None = None
|
|
174
|
+
enable_web_search: bool = False
|
|
174
175
|
|
|
175
176
|
def updated_with(self, param_name: str, value: Any) -> LLMOptions:
|
|
176
177
|
"""Update option from an action parameter."""
|
|
@@ -543,8 +544,8 @@ class Action(ABC):
|
|
|
543
544
|
def preassemble_result(self, context: ActionContext) -> ActionResult | None:
|
|
544
545
|
"""
|
|
545
546
|
Actions can have a separate preliminary step to pre-assemble outputs. This allows
|
|
546
|
-
us to determine
|
|
547
|
-
|
|
547
|
+
us to determine thew expected shape of the expected output and check if it already
|
|
548
|
+
exists.
|
|
548
549
|
|
|
549
550
|
For now, this only applies to actions with a single output, when `self.cacheable`
|
|
550
551
|
is True.
|
|
@@ -568,7 +569,10 @@ class Action(ABC):
|
|
|
568
569
|
self.name,
|
|
569
570
|
)
|
|
570
571
|
output_type = ItemType.doc
|
|
571
|
-
|
|
572
|
+
output_format = context.action.output_format or primary_input.format
|
|
573
|
+
primary_output = primary_input.derived_copy(
|
|
574
|
+
context, 0, type=output_type, format=output_format
|
|
575
|
+
)
|
|
572
576
|
log.info("Preassembled output: source %s, %s", primary_output.source, primary_output)
|
|
573
577
|
return ActionResult([primary_output])
|
|
574
578
|
else:
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
from enum import
|
|
1
|
+
from enum import StrEnum
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel
|
|
4
4
|
|
|
5
5
|
from kash.exec_model.commands_model import CommentedCommand
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
class Confidence(
|
|
8
|
+
class Confidence(StrEnum):
|
|
9
9
|
"""
|
|
10
10
|
How confident the assistant is that the answer is correct.
|
|
11
11
|
"""
|
kash/model/items_model.py
CHANGED
|
@@ -193,9 +193,16 @@ class ItemId:
|
|
|
193
193
|
from kash.web_content.canon_url import canonicalize_url
|
|
194
194
|
|
|
195
195
|
item_id = None
|
|
196
|
-
if
|
|
196
|
+
if (
|
|
197
|
+
item.type == ItemType.resource
|
|
198
|
+
and item.format == Format.url
|
|
199
|
+
and item.url
|
|
200
|
+
and not item.source
|
|
201
|
+
):
|
|
202
|
+
# This is a plain URL resource, so its identity is its URL.
|
|
197
203
|
item_id = ItemId(item.type, IdType.url, canonicalize_url(item.url))
|
|
198
204
|
elif item.type == ItemType.concept and item.title:
|
|
205
|
+
# This is a concept, so its identity is its title.
|
|
199
206
|
item_id = ItemId(item.type, IdType.concept, canonicalize_concept(item.title))
|
|
200
207
|
elif item.source and item.source.cacheable and item.source.operation.has_known_inputs:
|
|
201
208
|
# We know the source of this and if the action was cacheable, we can create
|
kash/model/params_model.py
CHANGED
|
@@ -206,10 +206,10 @@ A list of parameter declarations, possibly with default values.
|
|
|
206
206
|
|
|
207
207
|
# These are the default models for typical use cases.
|
|
208
208
|
# The user may override them with parameters.
|
|
209
|
-
DEFAULT_CAREFUL_LLM = LLM.
|
|
210
|
-
DEFAULT_STRUCTURED_LLM = LLM.
|
|
211
|
-
DEFAULT_STANDARD_LLM = LLM.
|
|
212
|
-
DEFAULT_FAST_LLM = LLM.
|
|
209
|
+
DEFAULT_CAREFUL_LLM = LLM.claude_sonnet_4_5
|
|
210
|
+
DEFAULT_STRUCTURED_LLM = LLM.claude_sonnet_4_5
|
|
211
|
+
DEFAULT_STANDARD_LLM = LLM.claude_sonnet_4_5
|
|
212
|
+
DEFAULT_FAST_LLM = LLM.claude_haiku_4_5
|
|
213
213
|
|
|
214
214
|
|
|
215
215
|
# Parameters set globally such as in the workspace.
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import os
|
|
19
19
|
from dataclasses import dataclass
|
|
20
|
-
from enum import
|
|
20
|
+
from enum import StrEnum
|
|
21
21
|
|
|
22
22
|
NBSP = "\u00a0"
|
|
23
23
|
|
|
@@ -35,7 +35,7 @@ class Icon:
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
# fmt: off
|
|
38
|
-
class Icons(
|
|
38
|
+
class Icons(StrEnum):
|
|
39
39
|
ARCHIVE = '\uf410' #
|
|
40
40
|
AUDIO = "\uf001" #
|
|
41
41
|
BINARY = "\ueae8" #
|
kash/shell/output/kerm_codes.py
CHANGED
|
@@ -67,7 +67,7 @@ https://www.ethanheilman.com/x/28/index.html
|
|
|
67
67
|
# files, so that legacy shell commands automatically have tooltips with info
|
|
68
68
|
# about files).
|
|
69
69
|
|
|
70
|
-
from enum import
|
|
70
|
+
from enum import StrEnum
|
|
71
71
|
from html import escape
|
|
72
72
|
from typing import Annotated, Literal, Self, TypeAlias
|
|
73
73
|
from urllib.parse import parse_qs, quote, urlencode, urlparse
|
|
@@ -91,7 +91,7 @@ KUI_SCHEME = f"{KUI_PROTOCOL}//"
|
|
|
91
91
|
"""The Kerm code URI scheme for embedding UI elements into links."""
|
|
92
92
|
|
|
93
93
|
|
|
94
|
-
class UIActionType(
|
|
94
|
+
class UIActionType(StrEnum):
|
|
95
95
|
paste_text = "paste_text"
|
|
96
96
|
"""Default action for pasting text into the terminal. If value is omitted, paste the link text."""
|
|
97
97
|
|
|
@@ -120,7 +120,7 @@ class UIAction(BaseModel):
|
|
|
120
120
|
return self.model_dump_json()
|
|
121
121
|
|
|
122
122
|
|
|
123
|
-
class DisplayStyle(
|
|
123
|
+
class DisplayStyle(StrEnum):
|
|
124
124
|
"""
|
|
125
125
|
Style for text.
|
|
126
126
|
"""
|
|
@@ -157,14 +157,14 @@ class DisplayHints(BaseModel):
|
|
|
157
157
|
dimensions: Dimensions | None = Field(default=None, description="Dimensions.")
|
|
158
158
|
|
|
159
159
|
|
|
160
|
-
class UIRole(
|
|
160
|
+
class UIRole(StrEnum):
|
|
161
161
|
tooltip = "tooltip"
|
|
162
162
|
popover = "popover"
|
|
163
163
|
output = "output"
|
|
164
164
|
input = "input"
|
|
165
165
|
|
|
166
166
|
|
|
167
|
-
class UIElementType(
|
|
167
|
+
class UIElementType(StrEnum):
|
|
168
168
|
text_tooltip = "text_tooltip"
|
|
169
169
|
link_tooltip = "link_tooltip"
|
|
170
170
|
iframe_tooltip = "iframe_tooltip"
|
|
@@ -32,13 +32,11 @@ class CachingSession(requests.Session):
|
|
|
32
32
|
):
|
|
33
33
|
super().__init__()
|
|
34
34
|
self._limiter: Limiter | None = None
|
|
35
|
+
self._max_wait_secs = max_wait_secs
|
|
35
36
|
if limit and limit_interval_secs:
|
|
36
37
|
rate = Rate(limit, Duration.SECOND * limit_interval_secs)
|
|
37
38
|
bucket = InMemoryBucket([rate])
|
|
38
|
-
|
|
39
|
-
self._limiter = Limiter(
|
|
40
|
-
bucket, raise_when_fail=False, max_delay=Duration.SECOND * max_wait_secs
|
|
41
|
-
)
|
|
39
|
+
self._limiter = Limiter(bucket)
|
|
42
40
|
log.info(
|
|
43
41
|
"CachingSession: rate limiting requests with limit=%d, interval=%d, max_wait=%d",
|
|
44
42
|
limit,
|
|
@@ -56,9 +54,11 @@ class CachingSession(requests.Session):
|
|
|
56
54
|
|
|
57
55
|
def save(path: Path):
|
|
58
56
|
if self._limiter:
|
|
59
|
-
acquired = self._limiter.try_acquire(
|
|
57
|
+
acquired = self._limiter.try_acquire(
|
|
58
|
+
"caching_session_get", blocking=True, timeout=self._max_wait_secs
|
|
59
|
+
)
|
|
60
60
|
if not acquired:
|
|
61
|
-
# Generally shouldn't happen.
|
|
61
|
+
# Generally shouldn't happen with blocking=True and reasonable timeout.
|
|
62
62
|
raise RuntimeError("Rate limiter failed to acquire after maximum delay")
|
|
63
63
|
|
|
64
64
|
response = super(CachingSession, self).get(url, **kwargs)
|
|
@@ -94,7 +94,7 @@ content: |
|
|
|
94
94
|
from __future__ import annotations
|
|
95
95
|
|
|
96
96
|
from dataclasses import field
|
|
97
|
-
from enum import Enum
|
|
97
|
+
from enum import Enum, StrEnum
|
|
98
98
|
from io import StringIO
|
|
99
99
|
from pathlib import Path
|
|
100
100
|
from textwrap import dedent
|
|
@@ -106,7 +106,7 @@ from pydantic.dataclasses import dataclass
|
|
|
106
106
|
from sidematter_format import to_json_string
|
|
107
107
|
|
|
108
108
|
|
|
109
|
-
class ChatRole(
|
|
109
|
+
class ChatRole(StrEnum):
|
|
110
110
|
"""
|
|
111
111
|
The role of a message in a chat. Represents the "role" in LLM APIs but note we slightly
|
|
112
112
|
abuse this term to also represent other types of messages, such as commands issued
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from datetime import UTC, datetime
|
|
4
|
-
from enum import
|
|
4
|
+
from enum import StrEnum
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
@@ -20,7 +20,7 @@ if TYPE_CHECKING:
|
|
|
20
20
|
log = get_logger(__name__)
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
class SortOption(
|
|
23
|
+
class SortOption(StrEnum):
|
|
24
24
|
filename = "filename"
|
|
25
25
|
size = "size"
|
|
26
26
|
accessed = "accessed"
|
|
@@ -28,13 +28,13 @@ class SortOption(str, Enum):
|
|
|
28
28
|
modified = "modified"
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
class GroupByOption(
|
|
31
|
+
class GroupByOption(StrEnum):
|
|
32
32
|
flat = "flat"
|
|
33
33
|
parent = "parent"
|
|
34
34
|
suffix = "suffix"
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
class FileType(
|
|
37
|
+
class FileType(StrEnum):
|
|
38
38
|
file = "file"
|
|
39
39
|
dir = "dir"
|
|
40
40
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{% extends "simple_webpage.html.jinja" %}
|
|
2
2
|
|
|
3
3
|
{#
|
|
4
|
-
Extends the simple page with
|
|
5
|
-
|
|
4
|
+
Extends the simple page with YouTube popover player.
|
|
5
|
+
Safe to use instead of simple_webpage.html.jinja since it only adds
|
|
6
|
+
functionality for YouTube if applicable.
|
|
6
7
|
#}
|
|
7
8
|
|
|
8
9
|
{% block custom_styles %}
|
|
@@ -97,7 +97,7 @@ kash/exec/command_registry.py,sha256=1s2ogU8b8nqK_AEtslbr1eYrXCGDkeT30UrB7L0BRoM
|
|
|
97
97
|
kash/exec/fetch_url_items.py,sha256=Bb8i9YW_XfJHwIAh5yf2_zLXagyESkQF1LL1uNaQQx0,6345
|
|
98
98
|
kash/exec/history.py,sha256=l2XwHGBR1UgTGSFPSBE9mltmxvjR_5qFFO6d-Z008nc,1208
|
|
99
99
|
kash/exec/importing.py,sha256=xunmBapeUMNc6Zox7y6e_DZkidyWeouiFZpphajwSzc,1843
|
|
100
|
-
kash/exec/llm_transforms.py,sha256=
|
|
100
|
+
kash/exec/llm_transforms.py,sha256=2fxas6K2YcixVGpXKt0-nxlN2qc1SR3-O1KbE0sFKIg,4834
|
|
101
101
|
kash/exec/precondition_checks.py,sha256=HymxL7qm4Yz8V76Um5pKdIRnQ2N-p9rpQQi1fI38bNA,2139
|
|
102
102
|
kash/exec/precondition_registry.py,sha256=9O-01d2OrsYLuhqodVuWjouLR2ABJbUotAmfJNBCRzs,1439
|
|
103
103
|
kash/exec/preconditions.py,sha256=bwNuuPEnkymj24ySPTl8K5DEgTtB2NPGAm9cWaomhAk,5262
|
|
@@ -110,7 +110,7 @@ kash/exec_model/commands_model.py,sha256=iM8QhzA0tAas5OwF5liUfHtm45XIH1LcvCviuh3
|
|
|
110
110
|
kash/exec_model/script_model.py,sha256=1VG3LhkTmlKzHOYouZ92ZpOSKSCcsz3-tHNcFMQF788,5031
|
|
111
111
|
kash/exec_model/shell_model.py,sha256=LUhQivbpXlerM-DUzNY7BtctNBbn08Wto8CSSxQDxRU,568
|
|
112
112
|
kash/file_storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
113
|
-
kash/file_storage/file_store.py,sha256=
|
|
113
|
+
kash/file_storage/file_store.py,sha256=0re_Gp0NoN3KxsMPtU8RSrG3Jw_PelC2wqju07AGxTU,31634
|
|
114
114
|
kash/file_storage/item_file_format.py,sha256=QNNpvMDDNyBLLrIwy3yhNgN0Ktsvjh-_Uzkf2XQpI98,7531
|
|
115
115
|
kash/file_storage/item_id_index.py,sha256=aiDHomizFLO_Ui2i6n-YIF4RUosIsxRIQca35yCdIIk,4589
|
|
116
116
|
kash/file_storage/metadata_dirs.py,sha256=9AqO3S3SSY1dtvP2iLX--E4ui0VIzXttG8R040otfyg,3820
|
|
@@ -135,14 +135,14 @@ kash/llm_utils/custom_sliding_transforms.py,sha256=z07WCdBoiywBIGk2EXK3xY4t_6g8I
|
|
|
135
135
|
kash/llm_utils/fuzzy_parsing.py,sha256=bbG2Y7i5w6kxAVPAixyluv3MDS2hW_pkhnJpVOLHZQc,3278
|
|
136
136
|
kash/llm_utils/init_litellm.py,sha256=5Fn9uW4P7lfEO8Rk1EJJUzDEGNjw-PDvxFgHlKDf-Ok,409
|
|
137
137
|
kash/llm_utils/llm_api_keys.py,sha256=nTB9wSFfHTOXvqshSQCQGCPxUwOW1U7oslngya8nHkw,1168
|
|
138
|
-
kash/llm_utils/llm_completion.py,sha256=
|
|
138
|
+
kash/llm_utils/llm_completion.py,sha256=UNFNgJbgU8sAWXmSrMV9DGrQ_1x-0IeEbtvrDG_P4NE,9251
|
|
139
139
|
kash/llm_utils/llm_messages.py,sha256=70QwIIvdwo-h4Jfn_6MbEHb3LTUjUmzg_v_dU_Ey__g,1174
|
|
140
140
|
kash/llm_utils/llm_names.py,sha256=VZbdKnoeBx_luB5YQ-Rz37gMt3_FcueJdp40ZaQbpUA,3620
|
|
141
|
-
kash/llm_utils/llms.py,sha256=
|
|
141
|
+
kash/llm_utils/llms.py,sha256=sGDrTnYAqjg_keKhXa7JR3HHkp5Klt-OhO3t9YjuhVQ,4036
|
|
142
142
|
kash/local_server/__init__.py,sha256=AyNpvCOJlQF6A4DnlYKRMbbfRNzdizEA-ytp-F2SLZU,162
|
|
143
143
|
kash/local_server/local_server.py,sha256=EugjL30VM0pWdZDsiQxU-o6EdEa082qlGd_7RHvI5tk,5863
|
|
144
144
|
kash/local_server/local_server_commands.py,sha256=T5wN-Xty3IbwbyeJxTULPB2NqssWLJcuV8IoqMu9bus,1668
|
|
145
|
-
kash/local_server/local_server_routes.py,sha256=
|
|
145
|
+
kash/local_server/local_server_routes.py,sha256=Qx9I2GLoACLYhTlT8-SxbnFe-SKqfhWB6wDMDSEQD2s,10531
|
|
146
146
|
kash/local_server/local_url_formatters.py,sha256=SqHjGMEufvm43n34SCa_8Asdwm7utx91Wwymj15TuSY,5327
|
|
147
147
|
kash/local_server/port_tools.py,sha256=oFfOvO6keqS5GowTpVg2FTu5KqkPHBq-dWAEomUIgGo,2008
|
|
148
148
|
kash/local_server/rich_html_template.py,sha256=O9CnkMYkWuMvKJkqD0P8jaZqfUe6hMP4LXFvcLpwN8Q,196
|
|
@@ -159,23 +159,23 @@ kash/media_base/media_cache.py,sha256=wNguo9nNnCRmr7GERrzDOj83xCYife7EnVvC2tlNtr
|
|
|
159
159
|
kash/media_base/media_services.py,sha256=kmAjLIrG62twI8GCowSeR1yfpVWf1KfAhPbuxPiaQAA,5475
|
|
160
160
|
kash/media_base/media_tools.py,sha256=enzSebW41vDBGWUwkEn5udhRHmSBvH01MAt5rY1s388,1466
|
|
161
161
|
kash/media_base/timestamp_citations.py,sha256=IHTvlZD3lIfe8T2uHFitgom82WahdHBeKqyc2OjUi9g,2368
|
|
162
|
-
kash/media_base/transcription_deepgram.py,sha256=
|
|
162
|
+
kash/media_base/transcription_deepgram.py,sha256=IXuGB8yRc4EMANCObxfedrAHktE1hVJGna-ZUkFCnf0,5191
|
|
163
163
|
kash/media_base/transcription_format.py,sha256=rOVPTpwvW22c27BRwYF-Tc_xzqK_wOtUZpOPlvkHiDY,2344
|
|
164
164
|
kash/media_base/transcription_whisper.py,sha256=GqvroW9kBAH4-gcbYkMgNCfs2MpMIgm1ip3NMWtJ0IE,1169
|
|
165
165
|
kash/media_base/services/local_file_media.py,sha256=_NV-T90rShJ8ucUjQXMPCKKJ50GSFE9PyyVzhXp5z9w,5624
|
|
166
166
|
kash/model/__init__.py,sha256=kFfBKb5N70NWYUfpRRxn_Sb9p_vXlB6BBaTCqWmSReo,2978
|
|
167
|
-
kash/model/actions_model.py,sha256=
|
|
168
|
-
kash/model/assistant_response_model.py,sha256=
|
|
167
|
+
kash/model/actions_model.py,sha256=I87Gb2nU6xelEuM8WFuuHWDqczjnlbpBYkw6wWIYkbo,23825
|
|
168
|
+
kash/model/assistant_response_model.py,sha256=tS0PmVxhdRXpBM-qNUGB4opyXUf5R4Z_4750w6mYCbA,2654
|
|
169
169
|
kash/model/compound_actions_model.py,sha256=oYEtVKtQv-mA1abZkK7PvaM9xazVBUuk1z0geKBulak,6965
|
|
170
170
|
kash/model/concept_model.py,sha256=we2qOcy9Mv1q7XPfkDLp_CyO_-8DwAUfUYlpgy_jrFs,1011
|
|
171
171
|
kash/model/exec_model.py,sha256=3Su3NEmEtDoSuQSxvg75FYY_EdClSM5pwQK1i7_S88A,3131
|
|
172
172
|
kash/model/graph_model.py,sha256=T034y0E9OJtITd1g9zp9vll5pLscdatq6JoT08KvPZE,2724
|
|
173
|
-
kash/model/items_model.py,sha256=
|
|
173
|
+
kash/model/items_model.py,sha256=e-KCVhC6poWjocsxZVBa0A8gmehtsZRcIqhLVIna5Ho,40152
|
|
174
174
|
kash/model/language_list.py,sha256=I3RIbxTseVmPdhExQimimEv18Gmy2ImMbpXe0-_t1Qw,450
|
|
175
175
|
kash/model/llm_actions_model.py,sha256=a29uXVNfS2CiqvM7HPdC6H9A23rSQQihAideuBLMH8g,2110
|
|
176
176
|
kash/model/media_model.py,sha256=ZnlZ-FkswbAIGpUAuNqLce1WDZK-WbnwHn2ipg8x7-0,3511
|
|
177
177
|
kash/model/operations_model.py,sha256=WmU-xeWGsqMLVN369dQEyVGU8T7G_KyLLsj6YFc5sVw,6517
|
|
178
|
-
kash/model/params_model.py,sha256=
|
|
178
|
+
kash/model/params_model.py,sha256=PWyx2P9tt1zj8NpBnvFkn61_KCegFtTJ_FSPYSLnsiY,15121
|
|
179
179
|
kash/model/paths_model.py,sha256=KDFm7wan7hjObHbnV2rR8-jsyLTVqbKcwFdKeLFRtdM,15889
|
|
180
180
|
kash/model/preconditions_model.py,sha256=-IfsVR0NkQhq_3hUTXzK2bFYAd--3YjSwUiDKHVQQqk,2887
|
|
181
181
|
kash/shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -185,7 +185,7 @@ kash/shell/completions/completion_scoring.py,sha256=-svesm2cR1AA86jYcxlynXCBZON2
|
|
|
185
185
|
kash/shell/completions/completion_types.py,sha256=FocRXd6Df3Df0nL2Y1GevMx3FsljJwbQdVgWsIngpaQ,4793
|
|
186
186
|
kash/shell/completions/shell_completions.py,sha256=A0WWrm2lEwguasDMnDuaI8xGny9MhwGfNvCY3rHNUnw,8844
|
|
187
187
|
kash/shell/file_icons/color_for_format.py,sha256=bFuE1lwiyUkgWB3Gk3jrch-9EIQz9thILQiX_a5dGb8,2034
|
|
188
|
-
kash/shell/file_icons/nerd_icons.py,sha256=
|
|
188
|
+
kash/shell/file_icons/nerd_icons.py,sha256=fxqICNUFXMy9miZxpr3dXAIEfQ-zUMweP3Ph3YjSR7Y,36047
|
|
189
189
|
kash/shell/input/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
190
190
|
kash/shell/input/input_prompts.py,sha256=LkF7Q7HygBOVT1XzvC0dY7gfCVV0pedfwI5nlX-I6YA,3820
|
|
191
191
|
kash/shell/input/inquirer_settings.py,sha256=2zOtgE2DJNzl4vEiEb_Dt8SUeM1YWjeXhCRaAPOCScM,1645
|
|
@@ -193,7 +193,7 @@ kash/shell/input/param_inputs.py,sha256=FiGClMtMe0pv0y_45qJ9PKF61vn8SOPiNeh5yvH0
|
|
|
193
193
|
kash/shell/input/shell_confirm.py,sha256=A17HTxx_DPnis2503Q_LOEW8P9yIWvaj1zHVz4LSz_Q,1070
|
|
194
194
|
kash/shell/output/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
195
195
|
kash/shell/output/kerm_code_utils.py,sha256=92A4AV-IFKKZMWLNZnd_zksNFMBgE_VNXySyn0Kn6Zk,1673
|
|
196
|
-
kash/shell/output/kerm_codes.py,sha256=
|
|
196
|
+
kash/shell/output/kerm_codes.py,sha256=1ofHqH74XlUOH91_eLmn2PLx-yyd8usnbSKuJDczWqQ,18872
|
|
197
197
|
kash/shell/output/kmarkdown.py,sha256=RRB5b0Ip0KZ71vnJKFfvxerYkeDFTCVTlHqHfmMy80Y,3675
|
|
198
198
|
kash/shell/output/shell_formatting.py,sha256=oxmAeJ2j0ANYSUsL15CUv--KcGlQ6Wa_rywXSDlsZM4,3331
|
|
199
199
|
kash/shell/output/shell_output.py,sha256=yG-4YjQUkPQZASMRGcfVRUadOcRO6hm-eaAC74jms6c,11812
|
|
@@ -206,7 +206,7 @@ kash/shell/utils/shell_function_wrapper.py,sha256=fgUuVhocYMKLkGJJQJOER5nFMAvM0Z
|
|
|
206
206
|
kash/utils/__init__.py,sha256=4Jl_AtgRADdGORimWhYZwbSfQSpQ6SiexNIZzmbcngI,111
|
|
207
207
|
kash/utils/errors.py,sha256=2lPL0fxI8pPOiDvjl0j-rvwY8uhmWetsrYYIc2-x1WY,3906
|
|
208
208
|
kash/utils/api_utils/api_retries.py,sha256=TtgxLxoMnXIzYMKbMUzsnVcPf-aKFm3cJ95zOcSeae8,21844
|
|
209
|
-
kash/utils/api_utils/cache_requests_limited.py,sha256=
|
|
209
|
+
kash/utils/api_utils/cache_requests_limited.py,sha256=4beytcBbZYuCXbT1QK8LaD98GBLnT3mcvjhFkNN0YII,3127
|
|
210
210
|
kash/utils/api_utils/gather_limited.py,sha256=6K0Z3u_NeX9wBfFFk21wUQeSimaDIm53AHlGYRLD6LQ,33018
|
|
211
211
|
kash/utils/api_utils/http_utils.py,sha256=Ou6QNiba5w7n71cgNmV168OFTLmMDNxWW5MM-XkFEME,1461
|
|
212
212
|
kash/utils/api_utils/multitask_gather.py,sha256=LAylwWZ2APbv-O_l0kLwBfP762D0qswMBV8ID4eCOA0,4446
|
|
@@ -228,14 +228,14 @@ kash/utils/common/type_utils.py,sha256=SJirXhPilQom_-OKkFToDLm_82ZwpjcNjRy8U1HaQ
|
|
|
228
228
|
kash/utils/common/uniquifier.py,sha256=75OY4KIVF8u1eoO0FCPbEGTyVpPOtM-0ctoG_s_jahM,3082
|
|
229
229
|
kash/utils/common/url.py,sha256=u4qT0sWYsuEYazFCr3IIpmrR6nXyATH-_6GHM2xF5E0,9689
|
|
230
230
|
kash/utils/common/url_slice.py,sha256=QJb_qJp-hd5lFrxpw7P009yeMTJWDMfF11KRKEo7mIA,10963
|
|
231
|
-
kash/utils/file_formats/chat_format.py,sha256=
|
|
231
|
+
kash/utils/file_formats/chat_format.py,sha256=MY2Gz09p8c_-MxS8l2WkGAOP8os9Sw8c_ZcKrpqEzN4,11908
|
|
232
232
|
kash/utils/file_utils/__init__.py,sha256=loL_iW0oOZs0mJ5GelBPptBcqzYKSWdsGcHrpRyxitQ,43
|
|
233
233
|
kash/utils/file_utils/csv_utils.py,sha256=ZqchXD4y0buWtgnEsR_UeHyWBHM1wEJl5u-IxQvFa3s,4064
|
|
234
234
|
kash/utils/file_utils/dir_info.py,sha256=HamMr58k_DanTLifj7A2JDxTGWXEZZx2pQuE6Hjcm8g,1856
|
|
235
235
|
kash/utils/file_utils/file_ext.py,sha256=U0fG3rowgtc56fNhhCK8P1UCYFbCNoa87pv7mGiEQgA,1876
|
|
236
236
|
kash/utils/file_utils/file_formats.py,sha256=4bq0-ZomFidL2GJBFyszGPurNQeTMOdLaXlGgrXznhA,4973
|
|
237
237
|
kash/utils/file_utils/file_formats_model.py,sha256=WqtAb10_vBuWeP2cUHzUHNjNmLx5GdqPjsnuqziB6Zg,15970
|
|
238
|
-
kash/utils/file_utils/file_sort_filter.py,sha256=
|
|
238
|
+
kash/utils/file_utils/file_sort_filter.py,sha256=Y-0Yw9-CaG0LMIaVo9dSTI-eLlvIzmnU0MoeJwMJBs0,7133
|
|
239
239
|
kash/utils/file_utils/file_walk.py,sha256=cpwVDPuaVm95_ZwFJiAdIuZAGhASI3gJ3ZUsCGP75b8,5527
|
|
240
240
|
kash/utils/file_utils/filename_parsing.py,sha256=drHrH2B9W_5yAbXURNGJxNqj9GmTe8FayH6Gjw9e4-U,4194
|
|
241
241
|
kash/utils/file_utils/ignore_files.py,sha256=QJ0SFeGdxSCaf4v45qQE_BMsMT5nOgomma0TuJRibp8,3546
|
|
@@ -277,7 +277,7 @@ kash/web_gen/templates/explain_view.html.jinja,sha256=DNw5Iw5SrhIUFRGB4qNvfcKXsB
|
|
|
277
277
|
kash/web_gen/templates/item_view.html.jinja,sha256=_b51RuoBmYu7nxVq-S_zw_tv8mfQXHICGqfDWNIB9Xg,7304
|
|
278
278
|
kash/web_gen/templates/simple_webpage.html.jinja,sha256=_RVu0AvrN5fK_Kz-tEi4AlPQ_wuu8-S9oFIYg_sdcec,2556
|
|
279
279
|
kash/web_gen/templates/tabbed_webpage.html.jinja,sha256=umkipUXW-lDGnbV-tlDroCfCx_385PFnpbzsvwmityo,1843
|
|
280
|
-
kash/web_gen/templates/youtube_webpage.html.jinja,sha256=
|
|
280
|
+
kash/web_gen/templates/youtube_webpage.html.jinja,sha256=eEvWXQsqEIapH0-0nXfG1SGh4BAmbxKIMmvZMcteYQE,1397
|
|
281
281
|
kash/web_gen/templates/components/toc_scripts.js.jinja,sha256=9AanLJaVormGi52h-k2tKJTRT4BiBGGNnw3Kmrnr40Q,10481
|
|
282
282
|
kash/web_gen/templates/components/toc_styles.css.jinja,sha256=SM99C9bOu11qdZ1U6hN7lLe2w_Hk6u9qNZcx2knSkgg,7553
|
|
283
283
|
kash/web_gen/templates/components/tooltip_scripts.js.jinja,sha256=63HUSXtT07Vh2ndp90ViuPHTdzslrkGO5it4s-5EheM,40181
|
|
@@ -305,8 +305,8 @@ kash/xonsh_custom/xonsh_modern_tools.py,sha256=mj_b34LZXfE8MJe9EpDmp5JZ0tDM1biYN
|
|
|
305
305
|
kash/xonsh_custom/xonsh_ranking_completer.py,sha256=ZRGiAfoEgqgnlq2-ReUVEaX5oOgW1DQ9WxIv2OJLuTo,5620
|
|
306
306
|
kash/xontrib/fnm.py,sha256=V2tsOdmIDgbFbZSfMLpsvDIwwJJqiYnOkOySD1cXNXw,3700
|
|
307
307
|
kash/xontrib/kash_extension.py,sha256=FLIMlgR3C_6A1fwKE-Ul0nmmpJSszVPbAriinUyQ8Zg,1896
|
|
308
|
-
kash_shell-0.3.
|
|
309
|
-
kash_shell-0.3.
|
|
310
|
-
kash_shell-0.3.
|
|
311
|
-
kash_shell-0.3.
|
|
312
|
-
kash_shell-0.3.
|
|
308
|
+
kash_shell-0.3.37.dist-info/METADATA,sha256=Nl6PtqxydXQXFJu9v7IKaioebse690jbQ68AB4myiXQ,33581
|
|
309
|
+
kash_shell-0.3.37.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
310
|
+
kash_shell-0.3.37.dist-info/entry_points.txt,sha256=SQraWDAo8SqYpthLXThei0mf_hGGyhYBUO-Er_0HcwI,85
|
|
311
|
+
kash_shell-0.3.37.dist-info/licenses/LICENSE,sha256=rCh2PsfYeiU6FK_0wb58kHGm_Fj5c43fdcHEexiVzIo,34562
|
|
312
|
+
kash_shell-0.3.37.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|