kash-shell 0.3.10__py3-none-any.whl → 0.3.12__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/actions/core/format_markdown_template.py +2 -5
- kash/actions/core/markdownify.py +2 -4
- kash/actions/core/readability.py +2 -4
- kash/actions/core/render_as_html.py +30 -11
- kash/actions/core/show_webpage.py +6 -11
- kash/actions/core/strip_html.py +4 -8
- kash/actions/core/{webpage_config.py → tabbed_webpage_config.py} +5 -3
- kash/actions/core/{webpage_generate.py → tabbed_webpage_generate.py} +5 -4
- kash/commands/base/basic_file_commands.py +21 -3
- kash/commands/base/files_command.py +29 -10
- kash/commands/extras/parse_uv_lock.py +12 -3
- kash/commands/workspace/selection_commands.py +1 -1
- kash/commands/workspace/workspace_commands.py +2 -3
- kash/config/colors.py +2 -2
- kash/config/env_settings.py +2 -42
- kash/config/logger.py +30 -25
- kash/config/logger_basic.py +6 -6
- kash/config/settings.py +23 -7
- kash/config/setup.py +33 -5
- kash/config/text_styles.py +25 -22
- kash/embeddings/cosine.py +12 -4
- kash/embeddings/embeddings.py +16 -6
- kash/embeddings/text_similarity.py +10 -4
- kash/exec/__init__.py +3 -0
- kash/exec/action_decorators.py +10 -25
- kash/exec/action_exec.py +43 -23
- kash/exec/llm_transforms.py +6 -3
- kash/exec/preconditions.py +10 -12
- kash/exec/resolve_args.py +4 -0
- kash/exec/runtime_settings.py +134 -0
- kash/exec/shell_callable_action.py +5 -3
- kash/file_storage/file_store.py +37 -38
- kash/file_storage/item_file_format.py +6 -3
- kash/file_storage/store_filenames.py +6 -3
- kash/help/function_param_info.py +1 -1
- kash/llm_utils/init_litellm.py +16 -0
- kash/llm_utils/llm_api_keys.py +6 -2
- kash/llm_utils/llm_completion.py +11 -4
- kash/local_server/local_server_routes.py +1 -7
- kash/mcp/mcp_cli.py +3 -2
- kash/mcp/mcp_server_routes.py +11 -12
- kash/media_base/transcription_deepgram.py +15 -2
- kash/model/__init__.py +1 -1
- kash/model/actions_model.py +6 -54
- kash/model/exec_model.py +79 -0
- kash/model/items_model.py +102 -35
- kash/model/operations_model.py +38 -15
- kash/model/paths_model.py +2 -0
- kash/shell/output/shell_output.py +10 -8
- kash/shell/shell_main.py +2 -2
- kash/shell/utils/exception_printing.py +2 -2
- kash/shell/utils/shell_function_wrapper.py +15 -15
- kash/text_handling/doc_normalization.py +16 -8
- kash/text_handling/markdown_render.py +1 -0
- kash/text_handling/markdown_utils.py +105 -2
- kash/utils/common/format_utils.py +2 -8
- kash/utils/common/function_inspect.py +360 -110
- kash/utils/common/inflection.py +22 -0
- kash/utils/common/task_stack.py +4 -15
- kash/utils/errors.py +14 -9
- kash/utils/file_utils/file_ext.py +4 -0
- kash/utils/file_utils/file_formats_model.py +32 -1
- kash/utils/file_utils/file_sort_filter.py +10 -3
- kash/web_gen/__init__.py +0 -4
- kash/web_gen/simple_webpage.py +52 -0
- kash/web_gen/tabbed_webpage.py +23 -16
- kash/web_gen/template_render.py +37 -2
- kash/web_gen/templates/base_styles.css.jinja +84 -59
- kash/web_gen/templates/base_webpage.html.jinja +85 -67
- kash/web_gen/templates/item_view.html.jinja +47 -37
- kash/web_gen/templates/simple_webpage.html.jinja +24 -0
- kash/web_gen/templates/tabbed_webpage.html.jinja +42 -32
- kash/workspaces/__init__.py +12 -3
- kash/workspaces/workspace_dirs.py +58 -0
- kash/workspaces/workspace_importing.py +1 -1
- kash/workspaces/workspaces.py +26 -90
- {kash_shell-0.3.10.dist-info → kash_shell-0.3.12.dist-info}/METADATA +7 -7
- {kash_shell-0.3.10.dist-info → kash_shell-0.3.12.dist-info}/RECORD +81 -76
- kash/shell/utils/argparse_utils.py +0 -20
- kash/utils/lang_utils/inflection.py +0 -18
- {kash_shell-0.3.10.dist-info → kash_shell-0.3.12.dist-info}/WHEEL +0 -0
- {kash_shell-0.3.10.dist-info → kash_shell-0.3.12.dist-info}/entry_points.txt +0 -0
- {kash_shell-0.3.10.dist-info → kash_shell-0.3.12.dist-info}/licenses/LICENSE +0 -0
kash/help/function_param_info.py
CHANGED
|
@@ -12,7 +12,7 @@ def _look_up_param_docs(func: Callable[..., Any], kw_params: list[FuncParam]) ->
|
|
|
12
12
|
name = func_param.name
|
|
13
13
|
param = ALL_COMMON_PARAMS.get(name)
|
|
14
14
|
if not param:
|
|
15
|
-
param = Param(name, description=None, type=func_param.
|
|
15
|
+
param = Param(name, description=None, type=func_param.effective_type or str)
|
|
16
16
|
|
|
17
17
|
# Also check the docstring for a description of this parameter.
|
|
18
18
|
docstring = parse_docstring(func.__doc__ or "")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from functools import cache
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@cache
|
|
5
|
+
def init_litellm():
|
|
6
|
+
"""
|
|
7
|
+
Configure litellm to suppress overly prominent exception messages.
|
|
8
|
+
Do this lazily since litellm is slow to import.
|
|
9
|
+
"""
|
|
10
|
+
try:
|
|
11
|
+
import litellm
|
|
12
|
+
from litellm import _logging # noqa: F401
|
|
13
|
+
|
|
14
|
+
litellm.suppress_debug_info = True # Suppress overly prominent exception messages.
|
|
15
|
+
except ImportError:
|
|
16
|
+
pass
|
kash/llm_utils/llm_api_keys.py
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import litellm
|
|
4
3
|
from clideps.env_vars.dotenv_utils import env_var_is_set
|
|
5
4
|
from clideps.env_vars.env_names import EnvName
|
|
6
|
-
from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider
|
|
7
5
|
|
|
6
|
+
from kash.llm_utils.init_litellm import init_litellm
|
|
8
7
|
from kash.llm_utils.llm_names import LLMName
|
|
9
8
|
from kash.llm_utils.llms import LLM
|
|
10
9
|
|
|
@@ -13,6 +12,11 @@ def api_for_model(model: LLMName) -> EnvName | None:
|
|
|
13
12
|
"""
|
|
14
13
|
Get the API key name for a model or None if not found.
|
|
15
14
|
"""
|
|
15
|
+
import litellm
|
|
16
|
+
from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider
|
|
17
|
+
|
|
18
|
+
init_litellm()
|
|
19
|
+
|
|
16
20
|
try:
|
|
17
21
|
_model, custom_llm_provider, _dynamic_api_key, _api_base = get_llm_provider(model)
|
|
18
22
|
except litellm.exceptions.BadRequestError:
|
kash/llm_utils/llm_completion.py
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import time
|
|
2
|
-
from typing import cast
|
|
4
|
+
from typing import TYPE_CHECKING, cast
|
|
3
5
|
|
|
4
|
-
import litellm
|
|
5
6
|
from flowmark import Wrap, fill_text
|
|
6
7
|
from funlog import format_duration, log_calls
|
|
7
|
-
from litellm.types.utils import Choices, ModelResponse
|
|
8
|
-
from litellm.types.utils import Message as LiteLLMMessage
|
|
9
8
|
from prettyfmt import slugify_snake
|
|
10
9
|
from pydantic import BaseModel
|
|
11
10
|
from pydantic.dataclasses import dataclass
|
|
@@ -13,12 +12,16 @@ from pydantic.dataclasses import dataclass
|
|
|
13
12
|
from kash.config.logger import get_logger
|
|
14
13
|
from kash.config.text_styles import EMOJI_TIMING
|
|
15
14
|
from kash.llm_utils.fuzzy_parsing import is_no_results
|
|
15
|
+
from kash.llm_utils.init_litellm import init_litellm
|
|
16
16
|
from kash.llm_utils.llm_messages import Message, MessageTemplate
|
|
17
17
|
from kash.llm_utils.llm_names import LLMName
|
|
18
18
|
from kash.utils.common.url import Url, is_url
|
|
19
19
|
from kash.utils.errors import ApiResultError
|
|
20
20
|
from kash.utils.file_formats.chat_format import ChatHistory, ChatMessage, ChatRole
|
|
21
21
|
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from litellm.types.utils import Message as LiteLLMMessage
|
|
24
|
+
|
|
22
25
|
log = get_logger(__name__)
|
|
23
26
|
|
|
24
27
|
|
|
@@ -68,6 +71,10 @@ def llm_completion(
|
|
|
68
71
|
"""
|
|
69
72
|
Perform an LLM completion with LiteLLM.
|
|
70
73
|
"""
|
|
74
|
+
import litellm
|
|
75
|
+
from litellm.types.utils import Choices, ModelResponse
|
|
76
|
+
|
|
77
|
+
init_litellm()
|
|
71
78
|
|
|
72
79
|
chat_history = ChatHistory.from_dicts(messages)
|
|
73
80
|
log.info(
|
|
@@ -18,7 +18,6 @@ from kash.shell.file_icons.nerd_icons import icon_for_file
|
|
|
18
18
|
from kash.shell.output.shell_output import Wrap
|
|
19
19
|
from kash.utils.common.type_utils import not_none
|
|
20
20
|
from kash.utils.errors import FileNotFound, InvalidFilename
|
|
21
|
-
from kash.web_gen import base_templates_dir
|
|
22
21
|
from kash.web_gen.template_render import render_web_template
|
|
23
22
|
from kash.workspaces.workspace_output import print_file_info
|
|
24
23
|
|
|
@@ -140,14 +139,11 @@ def explain(text: str):
|
|
|
140
139
|
|
|
141
140
|
return HTMLResponse(
|
|
142
141
|
render_web_template(
|
|
143
|
-
base_templates_dir,
|
|
144
142
|
"base_webpage.html.jinja",
|
|
145
143
|
{
|
|
146
144
|
"title": f"Help: {text}",
|
|
147
145
|
"content": render_web_template(
|
|
148
|
-
|
|
149
|
-
"explain_view.html.jinja",
|
|
150
|
-
{"help_html": help_html, "page_url": page_url},
|
|
146
|
+
"explain_view.html.jinja", {"help_html": help_html, "page_url": page_url}
|
|
151
147
|
),
|
|
152
148
|
},
|
|
153
149
|
)
|
|
@@ -270,12 +266,10 @@ def _serve_item(
|
|
|
270
266
|
|
|
271
267
|
return HTMLResponse(
|
|
272
268
|
render_web_template(
|
|
273
|
-
base_templates_dir,
|
|
274
269
|
"base_webpage.html.jinja",
|
|
275
270
|
{
|
|
276
271
|
"title": display_title,
|
|
277
272
|
"content": render_web_template(
|
|
278
|
-
base_templates_dir,
|
|
279
273
|
"item_view.html.jinja",
|
|
280
274
|
{
|
|
281
275
|
"item": item,
|
kash/mcp/mcp_cli.py
CHANGED
|
@@ -9,9 +9,10 @@ import logging
|
|
|
9
9
|
import os
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
|
|
12
|
+
from clideps.utils.readable_argparse import ReadableColorFormatter
|
|
13
|
+
|
|
12
14
|
from kash.config.settings import DEFAULT_MCP_SERVER_PORT, LogLevel, global_settings
|
|
13
15
|
from kash.config.setup import kash_setup
|
|
14
|
-
from kash.shell.utils.argparse_utils import WrappedColorFormatter
|
|
15
16
|
from kash.shell.version import get_version
|
|
16
17
|
|
|
17
18
|
__version__ = get_version()
|
|
@@ -27,7 +28,7 @@ log = logging.getLogger()
|
|
|
27
28
|
def build_parser():
|
|
28
29
|
from kash.workspaces.workspaces import global_ws_dir
|
|
29
30
|
|
|
30
|
-
parser = argparse.ArgumentParser(description=__doc__, formatter_class=
|
|
31
|
+
parser = argparse.ArgumentParser(description=__doc__, formatter_class=ReadableColorFormatter)
|
|
31
32
|
parser.add_argument(
|
|
32
33
|
"--version",
|
|
33
34
|
action="version",
|
kash/mcp/mcp_server_routes.py
CHANGED
|
@@ -13,12 +13,13 @@ from strif import AtomicVar
|
|
|
13
13
|
from kash.config.capture_output import CapturedOutput, captured_output
|
|
14
14
|
from kash.config.logger import get_logger
|
|
15
15
|
from kash.config.settings import global_settings
|
|
16
|
+
from kash.exec import kash_runtime
|
|
16
17
|
from kash.exec.action_exec import prepare_action_input, run_action_with_caching
|
|
17
18
|
from kash.exec.action_registry import get_all_actions_defaults, look_up_action_class
|
|
18
|
-
from kash.model.actions_model import Action, ActionResult
|
|
19
|
+
from kash.model.actions_model import Action, ActionResult
|
|
20
|
+
from kash.model.exec_model import ExecContext
|
|
19
21
|
from kash.model.params_model import TypedParamValues
|
|
20
22
|
from kash.model.paths_model import StorePath
|
|
21
|
-
from kash.workspaces.workspaces import current_ws, get_ws
|
|
22
23
|
|
|
23
24
|
log = get_logger(__name__)
|
|
24
25
|
|
|
@@ -214,9 +215,14 @@ def run_mcp_tool(action_name: str, arguments: dict) -> list[TextContent]:
|
|
|
214
215
|
# current workspace, which could be changed by the user by changing working
|
|
215
216
|
# directories. Maybe confusing?
|
|
216
217
|
explicit_mcp_ws = global_settings().mcp_ws_dir
|
|
217
|
-
ws = get_ws(explicit_mcp_ws) if explicit_mcp_ws else current_ws()
|
|
218
218
|
|
|
219
|
-
with
|
|
219
|
+
with kash_runtime(
|
|
220
|
+
workspace_dir=explicit_mcp_ws,
|
|
221
|
+
rerun=True, # Enabling rerun always for now, seems good for tools.
|
|
222
|
+
refetch=False, # Using the file caches.
|
|
223
|
+
# Keeping all transient files for now, but maybe make transient?
|
|
224
|
+
override_state=None,
|
|
225
|
+
) as exec_settings:
|
|
220
226
|
action_cls = look_up_action_class(action_name)
|
|
221
227
|
|
|
222
228
|
# Extract items array and remaining params from arguments.
|
|
@@ -228,14 +234,7 @@ def run_mcp_tool(action_name: str, arguments: dict) -> list[TextContent]:
|
|
|
228
234
|
action = action_cls.create(param_values)
|
|
229
235
|
|
|
230
236
|
# Create execution context and assemble action input.
|
|
231
|
-
context = ExecContext(
|
|
232
|
-
action=action,
|
|
233
|
-
workspace_dir=ws.base_dir,
|
|
234
|
-
rerun=True, # Enabling rerun always for now, seems good for tools.
|
|
235
|
-
refetch=False, # Using the file caches.
|
|
236
|
-
# Keeping all transient files for now, but maybe make transient?
|
|
237
|
-
override_state=None,
|
|
238
|
-
)
|
|
237
|
+
context = ExecContext(action=action, settings=exec_settings)
|
|
239
238
|
action_input = prepare_action_input(*input_items)
|
|
240
239
|
|
|
241
240
|
result, result_store_paths, _archived_store_paths = run_action_with_caching(
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from os.path import getsize
|
|
2
4
|
from pathlib import Path
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
3
6
|
|
|
4
7
|
from clideps.env_vars.dotenv_utils import load_dotenv_paths
|
|
5
|
-
from deepgram import ListenRESTClient, PrerecordedResponse
|
|
6
8
|
from httpx import Timeout
|
|
7
9
|
|
|
8
10
|
from kash.config.logger import CustomLogger, get_logger
|
|
@@ -10,6 +12,9 @@ from kash.config.settings import global_settings
|
|
|
10
12
|
from kash.media_base.transcription_format import SpeakerSegment, format_speaker_segments
|
|
11
13
|
from kash.utils.errors import ApiError, ContentError
|
|
12
14
|
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from deepgram import PrerecordedResponse
|
|
17
|
+
|
|
13
18
|
log: CustomLogger = get_logger(__name__)
|
|
14
19
|
|
|
15
20
|
|
|
@@ -19,7 +24,15 @@ def deepgram_transcribe_raw(
|
|
|
19
24
|
"""
|
|
20
25
|
Transcribe an audio file using Deepgram and return the raw response.
|
|
21
26
|
"""
|
|
22
|
-
|
|
27
|
+
# Slow import, do lazily.
|
|
28
|
+
from deepgram import (
|
|
29
|
+
ClientOptionsFromEnv,
|
|
30
|
+
DeepgramClient,
|
|
31
|
+
FileSource,
|
|
32
|
+
ListenRESTClient,
|
|
33
|
+
PrerecordedOptions,
|
|
34
|
+
PrerecordedResponse,
|
|
35
|
+
)
|
|
23
36
|
|
|
24
37
|
size = getsize(audio_file_path)
|
|
25
38
|
log.info(
|
kash/model/__init__.py
CHANGED
|
@@ -20,7 +20,6 @@ from kash.model.actions_model import (
|
|
|
20
20
|
Action,
|
|
21
21
|
ActionInput,
|
|
22
22
|
ActionResult,
|
|
23
|
-
ExecContext,
|
|
24
23
|
LLMOptions,
|
|
25
24
|
PathOp,
|
|
26
25
|
PathOpType,
|
|
@@ -33,6 +32,7 @@ from kash.model.compound_actions_model import (
|
|
|
33
32
|
look_up_actions,
|
|
34
33
|
)
|
|
35
34
|
from kash.model.concept_model import Concept, canonicalize_concept, normalize_concepts
|
|
35
|
+
from kash.model.exec_model import ExecContext
|
|
36
36
|
from kash.model.graph_model import GraphData, Link, Node
|
|
37
37
|
from kash.model.items_model import (
|
|
38
38
|
SLUG_MAX_LEN,
|
kash/model/actions_model.py
CHANGED
|
@@ -4,7 +4,6 @@ from abc import ABC, abstractmethod
|
|
|
4
4
|
from dataclasses import Field as DataclassField
|
|
5
5
|
from dataclasses import field, replace
|
|
6
6
|
from enum import Enum
|
|
7
|
-
from pathlib import Path
|
|
8
7
|
from textwrap import dedent
|
|
9
8
|
from typing import Any, TypeVar, cast
|
|
10
9
|
|
|
@@ -20,10 +19,10 @@ from typing_extensions import override
|
|
|
20
19
|
from kash.config.logger import get_logger
|
|
21
20
|
from kash.exec_model.args_model import NO_ARGS, ONE_ARG, ArgCount, ArgType, Signature
|
|
22
21
|
from kash.exec_model.shell_model import ShellResult
|
|
23
|
-
from kash.file_storage.file_store import FileStore
|
|
24
22
|
from kash.llm_utils import LLM, LLMName
|
|
25
23
|
from kash.llm_utils.llm_messages import Message, MessageTemplate
|
|
26
|
-
from kash.model.
|
|
24
|
+
from kash.model.exec_model import ExecContext
|
|
25
|
+
from kash.model.items_model import UNTITLED, Item, ItemType
|
|
27
26
|
from kash.model.operations_model import Operation, Source
|
|
28
27
|
from kash.model.params_model import (
|
|
29
28
|
ALL_COMMON_PARAMS,
|
|
@@ -38,7 +37,6 @@ from kash.model.preconditions_model import Precondition
|
|
|
38
37
|
from kash.utils.common.parse_key_vals import format_key_value
|
|
39
38
|
from kash.utils.common.type_utils import not_none
|
|
40
39
|
from kash.utils.errors import InvalidDefinition, InvalidInput
|
|
41
|
-
from kash.workspaces.workspaces import get_ws
|
|
42
40
|
|
|
43
41
|
log = get_logger(__name__)
|
|
44
42
|
|
|
@@ -64,53 +62,6 @@ class ActionInput:
|
|
|
64
62
|
return ActionInput(items=[])
|
|
65
63
|
|
|
66
64
|
|
|
67
|
-
@dataclass(frozen=True)
|
|
68
|
-
class ExecContext:
|
|
69
|
-
"""
|
|
70
|
-
An action and its context for execution. This is a good place for settings
|
|
71
|
-
that apply to any action and are bothersome to pass as parameters.
|
|
72
|
-
"""
|
|
73
|
-
|
|
74
|
-
action: Action
|
|
75
|
-
"""The action being executed."""
|
|
76
|
-
|
|
77
|
-
workspace_dir: Path
|
|
78
|
-
"""The workspace directory in which the action is being executed."""
|
|
79
|
-
|
|
80
|
-
rerun: bool = False
|
|
81
|
-
"""If True, always run actions, even cacheable ones that have results."""
|
|
82
|
-
|
|
83
|
-
refetch: bool = False
|
|
84
|
-
"""If True, will refetch items even if they are already in the content caches."""
|
|
85
|
-
|
|
86
|
-
override_state: State | None = None
|
|
87
|
-
"""If specified, override the state of result items. Useful to mark items as transient."""
|
|
88
|
-
|
|
89
|
-
tmp_output: bool = False
|
|
90
|
-
"""If True, will save output items to a temporary file."""
|
|
91
|
-
|
|
92
|
-
no_format: bool = False
|
|
93
|
-
"""If True, will not normalize the output item's body text formatting (for Markdown)."""
|
|
94
|
-
|
|
95
|
-
@property
|
|
96
|
-
def workspace(self) -> FileStore:
|
|
97
|
-
return get_ws(self.workspace_dir)
|
|
98
|
-
|
|
99
|
-
@property
|
|
100
|
-
def runtime_options(self) -> dict[str, str]:
|
|
101
|
-
"""Return non-default runtime options."""
|
|
102
|
-
opts: dict[str, str] = {}
|
|
103
|
-
# Only these two settings directly affect the output:
|
|
104
|
-
if self.no_format:
|
|
105
|
-
opts["no_format"] = "true"
|
|
106
|
-
if self.override_state:
|
|
107
|
-
opts["override_state"] = self.override_state.name
|
|
108
|
-
return opts
|
|
109
|
-
|
|
110
|
-
def __repr__(self):
|
|
111
|
-
return abbrev_obj(self, field_max_len=80)
|
|
112
|
-
|
|
113
|
-
|
|
114
65
|
class PathOpType(Enum):
|
|
115
66
|
archive = "archive"
|
|
116
67
|
select = "select"
|
|
@@ -365,8 +316,8 @@ class Action(ABC):
|
|
|
365
316
|
"""
|
|
366
317
|
Declaration sanity checks.
|
|
367
318
|
"""
|
|
368
|
-
if not self.name
|
|
369
|
-
raise InvalidDefinition("Action must have a name
|
|
319
|
+
if not self.name:
|
|
320
|
+
raise InvalidDefinition("Action must have a name")
|
|
370
321
|
|
|
371
322
|
for param in self.params:
|
|
372
323
|
if not self.has_param(param.name):
|
|
@@ -535,7 +486,7 @@ class Action(ABC):
|
|
|
535
486
|
log.info("Ignoring parameter for action `%s`: `%s`", self.name, param_name)
|
|
536
487
|
|
|
537
488
|
if overrides:
|
|
538
|
-
log.
|
|
489
|
+
log.info(
|
|
539
490
|
"Overriding parameters for action `%s`:\n%s",
|
|
540
491
|
self.name,
|
|
541
492
|
fmt_lines(overrides),
|
|
@@ -677,3 +628,4 @@ class PerItemAction(Action, ABC):
|
|
|
677
628
|
|
|
678
629
|
# Handle circular dependency in Python dataclasses.
|
|
679
630
|
rebuild_dataclass(Item) # pyright: ignore
|
|
631
|
+
rebuild_dataclass(ExecContext) # pyright: ignore
|
kash/model/exec_model.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from prettyfmt import abbrev_obj
|
|
7
|
+
from pydantic.dataclasses import dataclass
|
|
8
|
+
|
|
9
|
+
from kash.config.logger import get_logger
|
|
10
|
+
from kash.model.items_model import State
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from kash.file_storage.file_store import FileStore
|
|
14
|
+
from kash.model.actions_model import Action
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
log = get_logger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class RuntimeSettings:
|
|
22
|
+
"""
|
|
23
|
+
Workspace and other runtime settings that may be set across runs of
|
|
24
|
+
one or more actions.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
workspace_dir: Path
|
|
28
|
+
"""The workspace directory in which the action is being executed."""
|
|
29
|
+
|
|
30
|
+
rerun: bool = False
|
|
31
|
+
"""If True, always run actions, even cacheable ones that have results."""
|
|
32
|
+
|
|
33
|
+
refetch: bool = False
|
|
34
|
+
"""If True, will refetch items even if they are already in the content caches."""
|
|
35
|
+
|
|
36
|
+
override_state: State | None = None
|
|
37
|
+
"""If specified, override the state of result items. Useful to mark items as transient."""
|
|
38
|
+
|
|
39
|
+
tmp_output: bool = False
|
|
40
|
+
"""If True, will save output items to a temporary file."""
|
|
41
|
+
|
|
42
|
+
no_format: bool = False
|
|
43
|
+
"""If True, will not normalize the output item's body text formatting (for Markdown)."""
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def workspace(self) -> FileStore:
|
|
47
|
+
from kash.workspaces.workspaces import get_ws
|
|
48
|
+
|
|
49
|
+
return get_ws(self.workspace_dir)
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def non_default_options(self) -> dict[str, str]:
|
|
53
|
+
"""
|
|
54
|
+
Summarize non-default runtime options as a dict.
|
|
55
|
+
"""
|
|
56
|
+
opts: dict[str, str] = {}
|
|
57
|
+
# Only these two settings directly affect the output:
|
|
58
|
+
if self.no_format:
|
|
59
|
+
opts["no_format"] = "true"
|
|
60
|
+
if self.override_state:
|
|
61
|
+
opts["override_state"] = self.override_state.name
|
|
62
|
+
return opts
|
|
63
|
+
|
|
64
|
+
def __repr__(self):
|
|
65
|
+
return abbrev_obj(self, field_max_len=80)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass(frozen=True)
|
|
69
|
+
class ExecContext:
|
|
70
|
+
"""
|
|
71
|
+
An action and its context for execution. This is a good place for settings
|
|
72
|
+
that apply to any action and are bothersome to pass as parameters.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
action: Action
|
|
76
|
+
"""The action being executed."""
|
|
77
|
+
|
|
78
|
+
settings: RuntimeSettings
|
|
79
|
+
"""The workspace and other run-time settings for the action."""
|