kash-shell 0.3.0__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/__init__.py +2 -0
- kash/__main__.py +4 -0
- kash/actions/__init__.py +55 -0
- kash/actions/core/assistant_chat.py +45 -0
- kash/actions/core/chat.py +90 -0
- kash/actions/core/format_markdown_template.py +92 -0
- kash/actions/core/markdownify.py +29 -0
- kash/actions/core/readability.py +27 -0
- kash/actions/core/show_webpage.py +28 -0
- kash/actions/core/strip_html.py +28 -0
- kash/actions/core/summarize_as_bullets.py +53 -0
- kash/actions/core/webpage_config.py +21 -0
- kash/actions/core/webpage_generate.py +29 -0
- kash/actions/meta/write_instructions.py +39 -0
- kash/actions/meta/write_new_action.py +157 -0
- kash/commands/__init__.py +21 -0
- kash/commands/base/basic_file_commands.py +183 -0
- kash/commands/base/browser_commands.py +62 -0
- kash/commands/base/debug_commands.py +214 -0
- kash/commands/base/diff_commands.py +90 -0
- kash/commands/base/files_command.py +408 -0
- kash/commands/base/general_commands.py +104 -0
- kash/commands/base/global_state_commands.py +41 -0
- kash/commands/base/logs_commands.py +92 -0
- kash/commands/base/reformat_command.py +54 -0
- kash/commands/base/search_command.py +65 -0
- kash/commands/base/show_command.py +69 -0
- kash/commands/extras/utils_commands.py +27 -0
- kash/commands/help/assistant_commands.py +97 -0
- kash/commands/help/doc_commands.py +226 -0
- kash/commands/help/help_commands.py +133 -0
- kash/commands/workspace/selection_commands.py +200 -0
- kash/commands/workspace/workspace_commands.py +640 -0
- kash/concepts/concept_formats.py +23 -0
- kash/concepts/embeddings.py +130 -0
- kash/concepts/text_similarity.py +108 -0
- kash/config/__init__.py +4 -0
- kash/config/api_keys.py +84 -0
- kash/config/capture_output.py +77 -0
- kash/config/colors.py +279 -0
- kash/config/init.py +18 -0
- kash/config/lazy_imports.py +22 -0
- kash/config/logger.py +355 -0
- kash/config/logger_basic.py +35 -0
- kash/config/logo.txt +4 -0
- kash/config/logo_fancy.txt +4 -0
- kash/config/server_config.py +51 -0
- kash/config/settings.py +196 -0
- kash/config/setup.py +51 -0
- kash/config/suppress_warnings.py +27 -0
- kash/config/text_styles.py +426 -0
- kash/docs/__init__.py +0 -0
- kash/docs/all_docs.py +58 -0
- kash/docs/load_actions_info.py +28 -0
- kash/docs/load_api_docs.py +13 -0
- kash/docs/load_help_topics.py +47 -0
- kash/docs/load_source_code.py +125 -0
- kash/docs/markdown/api_docs_template.md +42 -0
- kash/docs/markdown/assistant_instructions_template.md +114 -0
- kash/docs/markdown/readme_template.md +26 -0
- kash/docs/markdown/topics/a1_what_is_kash.md +76 -0
- kash/docs/markdown/topics/a2_progress.md +96 -0
- kash/docs/markdown/topics/a3_installation.md +119 -0
- kash/docs/markdown/topics/a4_getting_started.md +300 -0
- kash/docs/markdown/topics/a5_tips_for_use_with_other_tools.md +83 -0
- kash/docs/markdown/topics/b0_philosophy_of_kash.md +177 -0
- kash/docs/markdown/topics/b1_kash_overview.md +124 -0
- kash/docs/markdown/topics/b2_workspace_and_file_formats.md +61 -0
- kash/docs/markdown/topics/b3_modern_shell_tool_recommendations.md +83 -0
- kash/docs/markdown/topics/b4_faq.md +166 -0
- kash/docs/markdown/warning.md +7 -0
- kash/docs/markdown/welcome.md +9 -0
- kash/docs_base/docs_base.py +85 -0
- kash/docs_base/load_custom_command_info.py +27 -0
- kash/docs_base/load_faqs.py +48 -0
- kash/docs_base/load_recipe_snippets.py +48 -0
- kash/docs_base/recipes/general_system_commands.ksh +10 -0
- kash/docs_base/recipes/python_dev_commands.ksh +7 -0
- kash/docs_base/recipes/tldr_standard_commands.ksh +2144 -0
- kash/errors.py +176 -0
- kash/exec/__init__.py +16 -0
- kash/exec/action_decorators.py +412 -0
- kash/exec/action_exec.py +457 -0
- kash/exec/action_registry.py +123 -0
- kash/exec/combiners.py +127 -0
- kash/exec/command_exec.py +34 -0
- kash/exec/command_registry.py +72 -0
- kash/exec/fetch_url_metadata.py +71 -0
- kash/exec/history.py +44 -0
- kash/exec/llm_transforms.py +121 -0
- kash/exec/precondition_checks.py +71 -0
- kash/exec/precondition_registry.py +43 -0
- kash/exec/preconditions.py +152 -0
- kash/exec/resolve_args.py +123 -0
- kash/exec/shell_callable_action.py +90 -0
- kash/exec_model/__init__.py +0 -0
- kash/exec_model/args_model.py +93 -0
- kash/exec_model/commands_model.py +163 -0
- kash/exec_model/script_model.py +161 -0
- kash/exec_model/shell_model.py +21 -0
- kash/file_storage/__init__.py +0 -0
- kash/file_storage/file_store.py +642 -0
- kash/file_storage/item_file_format.py +152 -0
- kash/file_storage/metadata_dirs.py +108 -0
- kash/file_storage/mtime_cache.py +108 -0
- kash/file_storage/persisted_yaml.py +37 -0
- kash/file_storage/store_cache_warmer.py +37 -0
- kash/file_storage/store_filenames.py +53 -0
- kash/form_input/__init__.py +0 -0
- kash/form_input/prompt_input.py +44 -0
- kash/help/__init__.py +0 -0
- kash/help/assistant.py +324 -0
- kash/help/assistant_instructions.py +68 -0
- kash/help/assistant_output.py +43 -0
- kash/help/docstring_utils.py +111 -0
- kash/help/function_param_info.py +44 -0
- kash/help/help_embeddings.py +85 -0
- kash/help/help_lookups.py +60 -0
- kash/help/help_pages.py +122 -0
- kash/help/help_printing.py +169 -0
- kash/help/help_types.py +247 -0
- kash/help/recommended_commands.py +143 -0
- kash/help/tldr_help.py +296 -0
- kash/llm_utils/__init__.py +0 -0
- kash/llm_utils/chat_format.py +413 -0
- kash/llm_utils/clean_headings.py +65 -0
- kash/llm_utils/fuzzy_parsing.py +119 -0
- kash/llm_utils/language_models.py +178 -0
- kash/llm_utils/llm_completion.py +172 -0
- kash/llm_utils/llm_messages.py +36 -0
- kash/local_server/__init__.py +2 -0
- kash/local_server/local_server.py +183 -0
- kash/local_server/local_server_commands.py +55 -0
- kash/local_server/local_server_routes.py +306 -0
- kash/local_server/local_url_formatters.py +169 -0
- kash/local_server/port_tools.py +67 -0
- kash/local_server/rich_html_template.py +12 -0
- kash/mcp/__init__.py +2 -0
- kash/mcp/mcp_main.py +67 -0
- kash/mcp/mcp_server_commands.py +57 -0
- kash/mcp/mcp_server_routes.py +256 -0
- kash/mcp/mcp_server_sse.py +143 -0
- kash/mcp/mcp_server_stdio.py +45 -0
- kash/media_base/__init__.py +0 -0
- kash/media_base/audio_processing.py +27 -0
- kash/media_base/media_cache.py +178 -0
- kash/media_base/media_services.py +112 -0
- kash/media_base/media_tools.py +48 -0
- kash/media_base/services/local_file_media.py +165 -0
- kash/media_base/speech_transcription.py +224 -0
- kash/media_base/timestamp_citations.py +80 -0
- kash/model/__init__.py +73 -0
- kash/model/actions_model.py +633 -0
- kash/model/assistant_response_model.py +87 -0
- kash/model/compound_actions_model.py +188 -0
- kash/model/graph_model.py +92 -0
- kash/model/items_model.py +821 -0
- kash/model/language_list.py +39 -0
- kash/model/llm_actions_model.py +63 -0
- kash/model/media_model.py +124 -0
- kash/model/operations_model.py +176 -0
- kash/model/params_model.py +435 -0
- kash/model/paths_model.py +458 -0
- kash/model/preconditions_model.py +98 -0
- kash/shell/__init__.py +0 -0
- kash/shell/completions/completion_scoring.py +280 -0
- kash/shell/completions/completion_types.py +154 -0
- kash/shell/completions/shell_completions.py +277 -0
- kash/shell/file_icons/color_for_format.py +70 -0
- kash/shell/file_icons/nerd_icons.py +946 -0
- kash/shell/output/__init__.py +0 -0
- kash/shell/output/kerm_code_utils.py +59 -0
- kash/shell/output/kerm_codes.py +588 -0
- kash/shell/output/kmarkdown.py +117 -0
- kash/shell/output/shell_output.py +477 -0
- kash/shell/ui/__init__.py +0 -0
- kash/shell/ui/shell_results.py +118 -0
- kash/shell/ui/shell_syntax.py +26 -0
- kash/shell/utils/exception_printing.py +50 -0
- kash/shell/utils/native_utils.py +240 -0
- kash/shell/utils/osc_utils.py +95 -0
- kash/shell/utils/shell_function_wrapper.py +204 -0
- kash/shell/utils/sys_tool_deps.py +289 -0
- kash/shell/utils/terminal_images.py +133 -0
- kash/shell_main.py +67 -0
- kash/text_handling/custom_sliding_transforms.py +266 -0
- kash/text_handling/doc_normalization.py +64 -0
- kash/text_handling/markdown_util.py +167 -0
- kash/text_handling/unified_diffs.py +138 -0
- kash/utils/__init__.py +4 -0
- kash/utils/common/__init__.py +4 -0
- kash/utils/common/atomic_var.py +147 -0
- kash/utils/common/format_utils.py +81 -0
- kash/utils/common/function_inspect.py +178 -0
- kash/utils/common/import_utils.py +89 -0
- kash/utils/common/lazyobject.py +144 -0
- kash/utils/common/obj_replace.py +78 -0
- kash/utils/common/parse_key_vals.py +85 -0
- kash/utils/common/parse_shell_args.py +348 -0
- kash/utils/common/stack_traces.py +49 -0
- kash/utils/common/string_replace.py +93 -0
- kash/utils/common/string_template.py +101 -0
- kash/utils/common/task_stack.py +162 -0
- kash/utils/common/type_utils.py +137 -0
- kash/utils/common/uniquifier.py +95 -0
- kash/utils/common/url.py +155 -0
- kash/utils/file_utils/__init__.py +3 -0
- kash/utils/file_utils/dir_size.py +48 -0
- kash/utils/file_utils/file_ext.py +86 -0
- kash/utils/file_utils/file_formats.py +134 -0
- kash/utils/file_utils/file_formats_model.py +408 -0
- kash/utils/file_utils/file_sort_filter.py +235 -0
- kash/utils/file_utils/file_walk.py +163 -0
- kash/utils/file_utils/filename_parsing.py +99 -0
- kash/utils/file_utils/git_tools.py +19 -0
- kash/utils/file_utils/ignore_files.py +166 -0
- kash/utils/file_utils/path_utils.py +36 -0
- kash/utils/lang_utils/__init__.py +0 -0
- kash/utils/lang_utils/capitalization.py +128 -0
- kash/utils/lang_utils/inflection.py +18 -0
- kash/utils/rich_custom/__init__.py +3 -0
- kash/utils/rich_custom/ansi_cell_len.py +72 -0
- kash/utils/rich_custom/rich_char_transform.py +89 -0
- kash/utils/rich_custom/rich_indent.py +69 -0
- kash/utils/rich_custom/rich_markdown_fork.py +771 -0
- kash/version.py +31 -0
- kash/web_content/canon_url.py +24 -0
- kash/web_content/dir_store.py +103 -0
- kash/web_content/file_cache_utils.py +117 -0
- kash/web_content/local_file_cache.py +247 -0
- kash/web_content/web_extract.py +55 -0
- kash/web_content/web_extract_justext.py +86 -0
- kash/web_content/web_extract_readabilipy.py +23 -0
- kash/web_content/web_fetch.py +101 -0
- kash/web_content/web_page_model.py +28 -0
- kash/web_gen/__init__.py +4 -0
- kash/web_gen/tabbed_webpage.py +149 -0
- kash/web_gen/template_render.py +29 -0
- kash/web_gen/templates/base_styles.css.jinja +192 -0
- kash/web_gen/templates/base_webpage.html.jinja +124 -0
- kash/web_gen/templates/content_styles.css.jinja +194 -0
- kash/web_gen/templates/explain_view.html.jinja +49 -0
- kash/web_gen/templates/item_view.html.jinja +294 -0
- kash/web_gen/templates/tabbed_webpage.html.jinja +49 -0
- kash/workspaces/__init__.py +13 -0
- kash/workspaces/param_state.py +24 -0
- kash/workspaces/selections.py +333 -0
- kash/workspaces/source_items.py +88 -0
- kash/workspaces/workspace_importing.py +56 -0
- kash/workspaces/workspace_names.py +33 -0
- kash/workspaces/workspace_output.py +154 -0
- kash/workspaces/workspace_registry.py +78 -0
- kash/workspaces/workspaces.py +197 -0
- kash/xonsh_custom/custom_shell.py +366 -0
- kash/xonsh_custom/customize_prompt.py +197 -0
- kash/xonsh_custom/customize_xonsh.py +112 -0
- kash/xonsh_custom/shell_load_commands.py +152 -0
- kash/xonsh_custom/shell_which.py +64 -0
- kash/xonsh_custom/xonsh_completers.py +715 -0
- kash/xonsh_custom/xonsh_env.py +28 -0
- kash/xonsh_custom/xonsh_modern_tools.py +56 -0
- kash/xonsh_custom/xonsh_ranking_completer.py +152 -0
- kash/xontrib/fnm.py +120 -0
- kash/xontrib/kash_extension.py +61 -0
- kash_shell-0.3.0.dist-info/METADATA +757 -0
- kash_shell-0.3.0.dist-info/RECORD +269 -0
- kash_shell-0.3.0.dist-info/WHEEL +4 -0
- kash_shell-0.3.0.dist-info/entry_points.txt +3 -0
- kash_shell-0.3.0.dist-info/licenses/LICENSE +664 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterable
|
|
4
|
+
from dataclasses import field, replace
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, Generic, TypeAlias, TypeVar
|
|
8
|
+
|
|
9
|
+
from chopdiff.docs import TextUnit
|
|
10
|
+
from prettyfmt import fmt_lines
|
|
11
|
+
from pydantic.dataclasses import dataclass
|
|
12
|
+
from pydantic.json_schema import JsonSchemaValue
|
|
13
|
+
|
|
14
|
+
from kash.config.logger import get_logger
|
|
15
|
+
from kash.errors import InvalidInput, InvalidParamName
|
|
16
|
+
from kash.llm_utils.language_models import LLM, LLMName
|
|
17
|
+
from kash.model.language_list import LANGUAGE_LIST
|
|
18
|
+
from kash.utils.common.parse_key_vals import format_key_value
|
|
19
|
+
from kash.utils.common.type_utils import instantiate_as_type
|
|
20
|
+
|
|
21
|
+
log = get_logger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
T = TypeVar("T")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class Param(Generic[T]):
|
|
29
|
+
"""
|
|
30
|
+
Describes a settable parameter. This describes the parameter itself (including type and
|
|
31
|
+
default value). It includes the (global) default value for the parameter but not its
|
|
32
|
+
actual value. May be used globally or as an option to a command or action.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
name: str
|
|
36
|
+
|
|
37
|
+
description: str | None
|
|
38
|
+
|
|
39
|
+
type: type[T]
|
|
40
|
+
|
|
41
|
+
default_value: T | None = None
|
|
42
|
+
"""
|
|
43
|
+
The default value for the parameter.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
is_explicit: bool = False
|
|
47
|
+
"""
|
|
48
|
+
Normally a parameter can have a global or action-specific default value. But if this
|
|
49
|
+
is true, the parameter is like an input that is always explicitly required at runtime
|
|
50
|
+
(like a query string).
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
valid_str_values: list[str] | None = None
|
|
54
|
+
"""
|
|
55
|
+
If the parameter is a string but has only certain allowed or suggested values,
|
|
56
|
+
list them here. Not necessary for enums, which are handled automatically.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
is_open_ended: bool = False
|
|
60
|
+
"""
|
|
61
|
+
If true and `valid_str_values` is set, the parameter can take any string value and
|
|
62
|
+
the `valid_str_values` are suggestions only.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
def __post_init__(self):
|
|
66
|
+
if not self.name or not self.name.replace("_", "").isalnum():
|
|
67
|
+
raise ValueError(f"Not a valid param name: {repr(self.name)}")
|
|
68
|
+
if self.default_value is not None and not isinstance(self.default_value, self.type):
|
|
69
|
+
raise TypeError(
|
|
70
|
+
f"Default value for param `{self.name}` must be an instance of {self.type}: {self.default_value}"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def default_value_str(self) -> str | None:
|
|
75
|
+
if self.default_value is None:
|
|
76
|
+
return None
|
|
77
|
+
elif issubclass(self.type, Enum):
|
|
78
|
+
return self.type(self.default_value).name
|
|
79
|
+
else:
|
|
80
|
+
return str(self.default_value)
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def valid_values(self) -> list[str]:
|
|
84
|
+
if self.valid_str_values:
|
|
85
|
+
return self.valid_str_values
|
|
86
|
+
elif issubclass(self.type, Enum):
|
|
87
|
+
# Use the enum names as the valid values.
|
|
88
|
+
return [e.name for e in self.type]
|
|
89
|
+
else:
|
|
90
|
+
return [] # Any value is allowed.
|
|
91
|
+
|
|
92
|
+
def validate_value(self, value: Any) -> None:
|
|
93
|
+
"""
|
|
94
|
+
For enum or closed str types, validate that the value is in the list of valid values.
|
|
95
|
+
"""
|
|
96
|
+
if self.valid_str_values and not self.is_open_ended and value not in self.valid_str_values:
|
|
97
|
+
raise InvalidInput(
|
|
98
|
+
f"Invalid value for parameter `{self.name}`: {value!r} not in allowed str values: {self.valid_str_values}"
|
|
99
|
+
)
|
|
100
|
+
elif issubclass(self.type, Enum) and value not in self.type:
|
|
101
|
+
raise InvalidInput(
|
|
102
|
+
f"Invalid value for parameter `{self.name}`: {value!r} not in allowed enum values: {list(self.type)}"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def full_description(self) -> str:
|
|
107
|
+
desc = self.description or ""
|
|
108
|
+
if desc:
|
|
109
|
+
desc += "\n\n"
|
|
110
|
+
desc += self.valid_and_default_values
|
|
111
|
+
return desc
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def valid_and_default_values(self) -> str:
|
|
115
|
+
doc_str = ""
|
|
116
|
+
if self.valid_values:
|
|
117
|
+
val_list = ", ".join(f"`{v}`" for v in self.valid_values)
|
|
118
|
+
if self.is_open_ended:
|
|
119
|
+
doc_str += f"Suggested values (open str type {self.type.__name__}): {val_list}"
|
|
120
|
+
else:
|
|
121
|
+
doc_str += f"Allowed values (type {self.type.__name__}): {val_list}"
|
|
122
|
+
if self.default_value:
|
|
123
|
+
if doc_str:
|
|
124
|
+
doc_str += "\n\n"
|
|
125
|
+
doc_str += f"Default value is: `{self.default_value}`"
|
|
126
|
+
return doc_str
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def is_bool(self) -> bool:
|
|
130
|
+
return issubclass(self.type, bool)
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def is_path(self) -> bool:
|
|
134
|
+
return issubclass(self.type, Path) or (
|
|
135
|
+
# XXX As a convenience, infer path types from the variable name..
|
|
136
|
+
issubclass(self.type, str) and self.name in ("path", "paths")
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def shell_prefix(self) -> str:
|
|
141
|
+
if self.is_bool:
|
|
142
|
+
return f"--{self.name}"
|
|
143
|
+
else:
|
|
144
|
+
return f"--{self.name}="
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def display(self) -> str:
|
|
148
|
+
if self.is_bool:
|
|
149
|
+
return f"{self.shell_prefix}"
|
|
150
|
+
else:
|
|
151
|
+
return f"{self.shell_prefix}VALUE"
|
|
152
|
+
|
|
153
|
+
def with_default(self, default: T) -> Param:
|
|
154
|
+
return replace(self, default_value=default)
|
|
155
|
+
|
|
156
|
+
def json_schema(self) -> JsonSchemaValue:
|
|
157
|
+
"""
|
|
158
|
+
Generate a JSON schema for this parameter.
|
|
159
|
+
"""
|
|
160
|
+
schema: JsonSchemaValue = {
|
|
161
|
+
"title": self.name,
|
|
162
|
+
"description": self.description or "",
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if issubclass(self.type, bool):
|
|
166
|
+
schema["type"] = "boolean"
|
|
167
|
+
elif issubclass(self.type, int):
|
|
168
|
+
schema["type"] = "integer"
|
|
169
|
+
elif issubclass(self.type, float):
|
|
170
|
+
schema["type"] = "number"
|
|
171
|
+
elif issubclass(self.type, str):
|
|
172
|
+
schema["type"] = "string"
|
|
173
|
+
if self.valid_str_values and not self.is_open_ended:
|
|
174
|
+
schema["enum"] = self.valid_str_values
|
|
175
|
+
elif issubclass(self.type, Enum):
|
|
176
|
+
# Enums serialized by value.
|
|
177
|
+
schema["type"] = "string"
|
|
178
|
+
schema["enum"] = [e.value for e in self.type]
|
|
179
|
+
else:
|
|
180
|
+
# Default to string for complex types.
|
|
181
|
+
schema["type"] = "string"
|
|
182
|
+
|
|
183
|
+
if self.default_value is not None:
|
|
184
|
+
if issubclass(self.type, Enum):
|
|
185
|
+
# Enums serialized by value.
|
|
186
|
+
schema["default"] = self.type(self.default_value).value
|
|
187
|
+
else:
|
|
188
|
+
schema["default"] = self.default_value
|
|
189
|
+
|
|
190
|
+
return schema
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
RawParamValue = str | bool
|
|
194
|
+
"""
|
|
195
|
+
Serialized string or boolean value for a parameter. May be converted to another type
|
|
196
|
+
like an enum. This type is compatible with command-line option values.
|
|
197
|
+
"""
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
ParamDeclarations: TypeAlias = tuple[Param, ...]
|
|
201
|
+
"""
|
|
202
|
+
A list of parameter declarations, possibly with default values.
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
# These are the default models for typical use cases.
|
|
207
|
+
# The user may override them with parameters.
|
|
208
|
+
DEFAULT_CAREFUL_LLM = LLM.o1_preview
|
|
209
|
+
DEFAULT_STRUCTURED_LLM = LLM.gpt_4o
|
|
210
|
+
DEFAULT_BASIC_LLM = LLM.claude_3_7_sonnet
|
|
211
|
+
DEFAULT_FAST_LLM = LLM.claude_3_5_haiku
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
# Parameters set globally such as in the workspace.
|
|
215
|
+
GLOBAL_PARAMS: dict[str, Param] = {
|
|
216
|
+
"careful_llm": Param(
|
|
217
|
+
"careful_llm",
|
|
218
|
+
"Default LLM used for complex, unstructured requests (including for the kash assistant).",
|
|
219
|
+
default_value=DEFAULT_CAREFUL_LLM,
|
|
220
|
+
type=LLMName,
|
|
221
|
+
valid_str_values=list(LLM),
|
|
222
|
+
is_open_ended=True,
|
|
223
|
+
),
|
|
224
|
+
"structured_llm": Param(
|
|
225
|
+
"structured_llm",
|
|
226
|
+
"Default LLM used for complex, structured requests (including for the kash assistant).",
|
|
227
|
+
default_value=DEFAULT_STRUCTURED_LLM,
|
|
228
|
+
type=LLMName,
|
|
229
|
+
valid_str_values=list(LLM),
|
|
230
|
+
is_open_ended=True,
|
|
231
|
+
),
|
|
232
|
+
"basic_llm": Param(
|
|
233
|
+
"basic_llm",
|
|
234
|
+
"Default LLM used for basic requests (including for the kash assistant).",
|
|
235
|
+
default_value=DEFAULT_BASIC_LLM,
|
|
236
|
+
type=LLMName,
|
|
237
|
+
valid_str_values=list(LLM),
|
|
238
|
+
is_open_ended=True,
|
|
239
|
+
),
|
|
240
|
+
"fast_llm": Param(
|
|
241
|
+
"fast_llm",
|
|
242
|
+
"Default LLM used for fast responses (including for the kash assistant).",
|
|
243
|
+
default_value=DEFAULT_FAST_LLM,
|
|
244
|
+
type=LLMName,
|
|
245
|
+
valid_str_values=list(LLM),
|
|
246
|
+
is_open_ended=True,
|
|
247
|
+
),
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
# Parameters that are common to all actions.
|
|
251
|
+
COMMON_ACTION_PARAMS: dict[str, Param] = {
|
|
252
|
+
"model": Param(
|
|
253
|
+
"model",
|
|
254
|
+
"The name of the LLM.",
|
|
255
|
+
default_value=None, # Let actions set defaults.
|
|
256
|
+
type=LLMName,
|
|
257
|
+
valid_str_values=list(LLM),
|
|
258
|
+
is_open_ended=True,
|
|
259
|
+
),
|
|
260
|
+
"language": Param(
|
|
261
|
+
"language",
|
|
262
|
+
"The language of the input audio or text.",
|
|
263
|
+
type=str,
|
|
264
|
+
default_value=None,
|
|
265
|
+
valid_str_values=LANGUAGE_LIST,
|
|
266
|
+
),
|
|
267
|
+
"chunk_size": Param(
|
|
268
|
+
"chunk_size",
|
|
269
|
+
"For actions that support it, process chunks of what size?",
|
|
270
|
+
default_value=None,
|
|
271
|
+
type=int,
|
|
272
|
+
),
|
|
273
|
+
"chunk_unit": Param(
|
|
274
|
+
"chunk_unit",
|
|
275
|
+
"For actions that support it, the unit for measuring chunk size.",
|
|
276
|
+
default_value=None,
|
|
277
|
+
type=TextUnit,
|
|
278
|
+
),
|
|
279
|
+
"query": Param(
|
|
280
|
+
"query",
|
|
281
|
+
"For search actions, the query to use.",
|
|
282
|
+
type=str,
|
|
283
|
+
default_value=None,
|
|
284
|
+
is_explicit=True,
|
|
285
|
+
),
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
# Extra parameters that are available when an action is invoked from the shell.
|
|
289
|
+
# Applies globally to all actions.
|
|
290
|
+
RUNTIME_ACTION_PARAMS: dict[str, Param] = {
|
|
291
|
+
"rerun": Param(
|
|
292
|
+
"rerun",
|
|
293
|
+
"Rerun an action that would otherwise be skipped because "
|
|
294
|
+
"it produces an output item that already exists.",
|
|
295
|
+
type=bool,
|
|
296
|
+
),
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
USER_SETTABLE_PARAMS: dict[str, Param] = {**GLOBAL_PARAMS, **COMMON_ACTION_PARAMS}
|
|
301
|
+
|
|
302
|
+
ALL_COMMON_PARAMS: dict[str, Param] = {
|
|
303
|
+
**GLOBAL_PARAMS,
|
|
304
|
+
**COMMON_ACTION_PARAMS,
|
|
305
|
+
**RUNTIME_ACTION_PARAMS,
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
HELP_PARAM = Param(
|
|
309
|
+
"help",
|
|
310
|
+
"Show full help for this command or action.",
|
|
311
|
+
type=bool,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
SHOW_SOURCE_PARAM = Param(
|
|
315
|
+
"show_source",
|
|
316
|
+
"Show the source code for this command or action.",
|
|
317
|
+
type=bool,
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
# Parameters present on all shell commands but not formally options to the
|
|
321
|
+
# commands or actions.
|
|
322
|
+
COMMON_SHELL_PARAMS: dict[str, Param] = {
|
|
323
|
+
"help": HELP_PARAM,
|
|
324
|
+
"show_source": SHOW_SOURCE_PARAM,
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def common_param(name: str) -> Param:
|
|
329
|
+
"""
|
|
330
|
+
Get a commonly used parameter by name.
|
|
331
|
+
"""
|
|
332
|
+
param = ALL_COMMON_PARAMS.get(name)
|
|
333
|
+
if param is None:
|
|
334
|
+
raise InvalidParamName(name)
|
|
335
|
+
return param
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def common_params(*names: str) -> tuple[Param, ...]:
|
|
339
|
+
"""
|
|
340
|
+
Get a set of commonly used parameters by name.
|
|
341
|
+
"""
|
|
342
|
+
return tuple(common_param(name) for name in names)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
@dataclass
|
|
346
|
+
class RawParamValues:
|
|
347
|
+
"""
|
|
348
|
+
A set of raw parameter values in raw (mostly untyped string or bool) format,
|
|
349
|
+
as they are read from the shell.
|
|
350
|
+
"""
|
|
351
|
+
|
|
352
|
+
values: dict[str, RawParamValue] = field(default_factory=dict)
|
|
353
|
+
|
|
354
|
+
def items(self):
|
|
355
|
+
return self.values.items()
|
|
356
|
+
|
|
357
|
+
def get_parsed_value(
|
|
358
|
+
self, param_name: str, type: type[T], param_info: dict[str, Param]
|
|
359
|
+
) -> T | None:
|
|
360
|
+
raw_value = self.values.get(param_name)
|
|
361
|
+
if raw_value is None:
|
|
362
|
+
param = param_info.get(param_name)
|
|
363
|
+
if param:
|
|
364
|
+
return param.default_value
|
|
365
|
+
else:
|
|
366
|
+
raise InvalidParamName(param_name)
|
|
367
|
+
else:
|
|
368
|
+
return instantiate_as_type(raw_value, type)
|
|
369
|
+
|
|
370
|
+
def parse_all(self, param_info: dict[str, Param]) -> TypedParamValues:
|
|
371
|
+
"""
|
|
372
|
+
Convert and validate all raw values to typed values, using the provided parameter info.
|
|
373
|
+
Any extra params in the provided `param_info` are ignored.
|
|
374
|
+
"""
|
|
375
|
+
applicable_params = {
|
|
376
|
+
name: param for name, param in param_info.items() if name in self.values.keys()
|
|
377
|
+
}
|
|
378
|
+
if len(applicable_params) != len(self.values):
|
|
379
|
+
raise InvalidInput(
|
|
380
|
+
f"Did not find matching params for the given parameter names: "
|
|
381
|
+
f"{', '.join(repr(k) for k in self.values.keys() - applicable_params.keys())}"
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
values = {
|
|
385
|
+
name: self.get_parsed_value(name, param.type, param_info)
|
|
386
|
+
for name, param in applicable_params.items()
|
|
387
|
+
}
|
|
388
|
+
typed_values = TypedParamValues(values=values, params=applicable_params)
|
|
389
|
+
|
|
390
|
+
log.info("Raw params: %s", self)
|
|
391
|
+
log.info("Parsed params: %s", typed_values)
|
|
392
|
+
return typed_values
|
|
393
|
+
|
|
394
|
+
def as_str(self) -> str:
|
|
395
|
+
if self.items():
|
|
396
|
+
return fmt_lines([format_key_value(name, value) for name, value in self.items()])
|
|
397
|
+
else:
|
|
398
|
+
return fmt_lines(["(no parameters)"])
|
|
399
|
+
|
|
400
|
+
def as_str_brief(self):
|
|
401
|
+
return str(self.values)
|
|
402
|
+
|
|
403
|
+
def __str__(self):
|
|
404
|
+
return self.as_str_brief()
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
@dataclass(frozen=True)
|
|
408
|
+
class TypedParamValues:
|
|
409
|
+
"""
|
|
410
|
+
A set of parameter values in typed format, with parameter info for
|
|
411
|
+
each value.
|
|
412
|
+
"""
|
|
413
|
+
|
|
414
|
+
def __post_init__(self):
|
|
415
|
+
if set(self.values.keys()) != set(self.params.keys()):
|
|
416
|
+
raise ValueError(
|
|
417
|
+
f"Parameter names in values and params must match: "
|
|
418
|
+
f"{sorted(self.values.keys())} != {sorted(self.params.keys())}"
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
@staticmethod
|
|
422
|
+
def create(values: dict[str, Any], param_info: Iterable[Param]) -> TypedParamValues:
|
|
423
|
+
"""
|
|
424
|
+
Create a `TypedParamValues`, checking that all values have corresponding
|
|
425
|
+
param info.
|
|
426
|
+
"""
|
|
427
|
+
params = {p.name: p for p in param_info if p.name in values}
|
|
428
|
+
if set(params.keys()) != set(values.keys()):
|
|
429
|
+
raise ValueError(
|
|
430
|
+
f"Missing params for supplied values: values for {sorted(values.keys())} but params for {sorted(params.keys())}"
|
|
431
|
+
)
|
|
432
|
+
return TypedParamValues(values=values, params=params)
|
|
433
|
+
|
|
434
|
+
values: dict[str, Any] = field(default_factory=dict)
|
|
435
|
+
params: dict[str, Param] = field(default_factory=dict)
|