zrb 1.21.29__py3-none-any.whl → 2.0.0a4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of zrb might be problematic. Click here for more details.
- zrb/__init__.py +118 -129
- zrb/builtin/__init__.py +54 -2
- zrb/builtin/llm/chat.py +147 -0
- zrb/callback/callback.py +8 -1
- zrb/cmd/cmd_result.py +2 -1
- zrb/config/config.py +491 -280
- zrb/config/helper.py +84 -0
- zrb/config/web_auth_config.py +50 -35
- zrb/context/any_shared_context.py +13 -2
- zrb/context/context.py +31 -3
- zrb/context/print_fn.py +13 -0
- zrb/context/shared_context.py +14 -1
- zrb/input/option_input.py +30 -2
- zrb/llm/agent/__init__.py +9 -0
- zrb/llm/agent/agent.py +215 -0
- zrb/llm/agent/summarizer.py +20 -0
- zrb/llm/app/__init__.py +10 -0
- zrb/llm/app/completion.py +281 -0
- zrb/llm/app/confirmation/allow_tool.py +66 -0
- zrb/llm/app/confirmation/handler.py +178 -0
- zrb/llm/app/confirmation/replace_confirmation.py +77 -0
- zrb/llm/app/keybinding.py +34 -0
- zrb/llm/app/layout.py +117 -0
- zrb/llm/app/lexer.py +155 -0
- zrb/llm/app/redirection.py +28 -0
- zrb/llm/app/style.py +16 -0
- zrb/llm/app/ui.py +733 -0
- zrb/llm/config/__init__.py +4 -0
- zrb/llm/config/config.py +122 -0
- zrb/llm/config/limiter.py +247 -0
- zrb/llm/history_manager/__init__.py +4 -0
- zrb/llm/history_manager/any_history_manager.py +23 -0
- zrb/llm/history_manager/file_history_manager.py +91 -0
- zrb/llm/history_processor/summarizer.py +108 -0
- zrb/llm/note/__init__.py +3 -0
- zrb/llm/note/manager.py +122 -0
- zrb/llm/prompt/__init__.py +29 -0
- zrb/llm/prompt/claude_compatibility.py +92 -0
- zrb/llm/prompt/compose.py +55 -0
- zrb/llm/prompt/default.py +51 -0
- zrb/llm/prompt/markdown/mandate.md +23 -0
- zrb/llm/prompt/markdown/persona.md +3 -0
- zrb/llm/prompt/markdown/summarizer.md +21 -0
- zrb/llm/prompt/note.py +41 -0
- zrb/llm/prompt/system_context.py +46 -0
- zrb/llm/prompt/zrb.py +41 -0
- zrb/llm/skill/__init__.py +3 -0
- zrb/llm/skill/manager.py +86 -0
- zrb/llm/task/__init__.py +4 -0
- zrb/llm/task/llm_chat_task.py +316 -0
- zrb/llm/task/llm_task.py +245 -0
- zrb/llm/tool/__init__.py +39 -0
- zrb/llm/tool/bash.py +75 -0
- zrb/llm/tool/code.py +266 -0
- zrb/llm/tool/file.py +419 -0
- zrb/llm/tool/note.py +70 -0
- zrb/{builtin/llm → llm}/tool/rag.py +8 -5
- zrb/llm/tool/search/brave.py +53 -0
- zrb/llm/tool/search/searxng.py +47 -0
- zrb/llm/tool/search/serpapi.py +47 -0
- zrb/llm/tool/skill.py +19 -0
- zrb/llm/tool/sub_agent.py +70 -0
- zrb/llm/tool/web.py +97 -0
- zrb/llm/tool/zrb_task.py +66 -0
- zrb/llm/util/attachment.py +101 -0
- zrb/llm/util/prompt.py +104 -0
- zrb/llm/util/stream_response.py +178 -0
- zrb/session/any_session.py +0 -3
- zrb/session/session.py +1 -1
- zrb/task/base/context.py +25 -13
- zrb/task/base/execution.py +52 -47
- zrb/task/base/lifecycle.py +7 -4
- zrb/task/base_task.py +48 -49
- zrb/task/base_trigger.py +4 -1
- zrb/task/cmd_task.py +6 -0
- zrb/task/http_check.py +11 -5
- zrb/task/make_task.py +3 -0
- zrb/task/rsync_task.py +5 -0
- zrb/task/scaffolder.py +7 -4
- zrb/task/scheduler.py +3 -0
- zrb/task/tcp_check.py +6 -4
- zrb/util/ascii_art/art/bee.txt +17 -0
- zrb/util/ascii_art/art/cat.txt +9 -0
- zrb/util/ascii_art/art/ghost.txt +16 -0
- zrb/util/ascii_art/art/panda.txt +17 -0
- zrb/util/ascii_art/art/rose.txt +14 -0
- zrb/util/ascii_art/art/unicorn.txt +15 -0
- zrb/util/ascii_art/banner.py +92 -0
- zrb/util/cli/markdown.py +22 -2
- zrb/util/cmd/command.py +33 -10
- zrb/util/file.py +51 -32
- zrb/util/match.py +78 -0
- zrb/util/run.py +3 -3
- {zrb-1.21.29.dist-info → zrb-2.0.0a4.dist-info}/METADATA +9 -15
- {zrb-1.21.29.dist-info → zrb-2.0.0a4.dist-info}/RECORD +100 -128
- zrb/attr/__init__.py +0 -0
- zrb/builtin/llm/attachment.py +0 -40
- zrb/builtin/llm/chat_completion.py +0 -274
- zrb/builtin/llm/chat_session.py +0 -270
- zrb/builtin/llm/chat_session_cmd.py +0 -288
- zrb/builtin/llm/chat_trigger.py +0 -79
- zrb/builtin/llm/history.py +0 -71
- zrb/builtin/llm/input.py +0 -27
- zrb/builtin/llm/llm_ask.py +0 -269
- zrb/builtin/llm/previous-session.js +0 -21
- zrb/builtin/llm/tool/__init__.py +0 -0
- zrb/builtin/llm/tool/api.py +0 -75
- zrb/builtin/llm/tool/cli.py +0 -52
- zrb/builtin/llm/tool/code.py +0 -236
- zrb/builtin/llm/tool/file.py +0 -560
- zrb/builtin/llm/tool/note.py +0 -84
- zrb/builtin/llm/tool/sub_agent.py +0 -150
- zrb/builtin/llm/tool/web.py +0 -171
- zrb/builtin/project/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/service/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/__init__.py +0 -0
- zrb/builtin/project/create/__init__.py +0 -0
- zrb/builtin/shell/__init__.py +0 -0
- zrb/builtin/shell/autocomplete/__init__.py +0 -0
- zrb/callback/__init__.py +0 -0
- zrb/cmd/__init__.py +0 -0
- zrb/config/default_prompt/interactive_system_prompt.md +0 -29
- zrb/config/default_prompt/persona.md +0 -1
- zrb/config/default_prompt/summarization_prompt.md +0 -57
- zrb/config/default_prompt/system_prompt.md +0 -38
- zrb/config/llm_config.py +0 -339
- zrb/config/llm_context/config.py +0 -166
- zrb/config/llm_context/config_parser.py +0 -40
- zrb/config/llm_context/workflow.py +0 -81
- zrb/config/llm_rate_limitter.py +0 -190
- zrb/content_transformer/__init__.py +0 -0
- zrb/context/__init__.py +0 -0
- zrb/dot_dict/__init__.py +0 -0
- zrb/env/__init__.py +0 -0
- zrb/group/__init__.py +0 -0
- zrb/input/__init__.py +0 -0
- zrb/runner/__init__.py +0 -0
- zrb/runner/web_route/__init__.py +0 -0
- zrb/runner/web_route/home_page/__init__.py +0 -0
- zrb/session/__init__.py +0 -0
- zrb/session_state_log/__init__.py +0 -0
- zrb/session_state_logger/__init__.py +0 -0
- zrb/task/__init__.py +0 -0
- zrb/task/base/__init__.py +0 -0
- zrb/task/llm/__init__.py +0 -0
- zrb/task/llm/agent.py +0 -204
- zrb/task/llm/agent_runner.py +0 -152
- zrb/task/llm/config.py +0 -122
- zrb/task/llm/conversation_history.py +0 -209
- zrb/task/llm/conversation_history_model.py +0 -67
- zrb/task/llm/default_workflow/coding/workflow.md +0 -41
- zrb/task/llm/default_workflow/copywriting/workflow.md +0 -68
- zrb/task/llm/default_workflow/git/workflow.md +0 -118
- zrb/task/llm/default_workflow/golang/workflow.md +0 -128
- zrb/task/llm/default_workflow/html-css/workflow.md +0 -135
- zrb/task/llm/default_workflow/java/workflow.md +0 -146
- zrb/task/llm/default_workflow/javascript/workflow.md +0 -158
- zrb/task/llm/default_workflow/python/workflow.md +0 -160
- zrb/task/llm/default_workflow/researching/workflow.md +0 -153
- zrb/task/llm/default_workflow/rust/workflow.md +0 -162
- zrb/task/llm/default_workflow/shell/workflow.md +0 -299
- zrb/task/llm/error.py +0 -95
- zrb/task/llm/file_replacement.py +0 -206
- zrb/task/llm/file_tool_model.py +0 -57
- zrb/task/llm/history_processor.py +0 -206
- zrb/task/llm/history_summarization.py +0 -25
- zrb/task/llm/print_node.py +0 -221
- zrb/task/llm/prompt.py +0 -321
- zrb/task/llm/subagent_conversation_history.py +0 -41
- zrb/task/llm/tool_wrapper.py +0 -361
- zrb/task/llm/typing.py +0 -3
- zrb/task/llm/workflow.py +0 -76
- zrb/task/llm_task.py +0 -379
- zrb/task_status/__init__.py +0 -0
- zrb/util/__init__.py +0 -0
- zrb/util/cli/__init__.py +0 -0
- zrb/util/cmd/__init__.py +0 -0
- zrb/util/codemod/__init__.py +0 -0
- zrb/util/string/__init__.py +0 -0
- zrb/xcom/__init__.py +0 -0
- /zrb/{config/default_prompt/file_extractor_system_prompt.md → llm/prompt/markdown/file_extractor.md} +0 -0
- /zrb/{config/default_prompt/repo_extractor_system_prompt.md → llm/prompt/markdown/repo_extractor.md} +0 -0
- /zrb/{config/default_prompt/repo_summarizer_system_prompt.md → llm/prompt/markdown/repo_summarizer.md} +0 -0
- {zrb-1.21.29.dist-info → zrb-2.0.0a4.dist-info}/WHEEL +0 -0
- {zrb-1.21.29.dist-info → zrb-2.0.0a4.dist-info}/entry_points.txt +0 -0
zrb/config/llm_config.py
DELETED
|
@@ -1,339 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from typing import TYPE_CHECKING, Any, Callable
|
|
3
|
-
|
|
4
|
-
from zrb.config.config import CFG
|
|
5
|
-
|
|
6
|
-
if TYPE_CHECKING:
|
|
7
|
-
from pydantic_ai.models import Model
|
|
8
|
-
from pydantic_ai.providers import Provider
|
|
9
|
-
from pydantic_ai.settings import ModelSettings
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class LLMConfig:
|
|
13
|
-
def __init__(
|
|
14
|
-
self,
|
|
15
|
-
default_model_name: str | None = None,
|
|
16
|
-
default_model_base_url: str | None = None,
|
|
17
|
-
default_model_api_key: str | None = None,
|
|
18
|
-
default_small_model_name: str | None = None,
|
|
19
|
-
default_small_model_base_url: str | None = None,
|
|
20
|
-
default_small_model_api_key: str | None = None,
|
|
21
|
-
default_persona: str | None = None,
|
|
22
|
-
default_system_prompt: str | None = None,
|
|
23
|
-
default_interactive_system_prompt: str | None = None,
|
|
24
|
-
default_special_instruction_prompt: str | None = None,
|
|
25
|
-
default_summarization_prompt: str | None = None,
|
|
26
|
-
default_summarize_history: bool | None = None,
|
|
27
|
-
default_history_summarization_token_threshold: int | None = None,
|
|
28
|
-
default_workflows: list[str] | None = None,
|
|
29
|
-
default_model: "Model | None" = None,
|
|
30
|
-
default_model_settings: "ModelSettings | None" = None,
|
|
31
|
-
default_model_provider: "Provider | None" = None,
|
|
32
|
-
default_small_model: "Model | None" = None,
|
|
33
|
-
default_small_model_settings: "ModelSettings | None" = None,
|
|
34
|
-
default_small_model_provider: "Provider | None" = None,
|
|
35
|
-
default_yolo_mode: bool | list[str] | None = None,
|
|
36
|
-
default_current_weather_tool: Callable | None = None,
|
|
37
|
-
default_current_location_tool: Callable | None = None,
|
|
38
|
-
default_search_internet_tool: Callable | None = None,
|
|
39
|
-
):
|
|
40
|
-
self.__internal_default_prompt: dict[str, str] = {}
|
|
41
|
-
self._default_model_name = default_model_name
|
|
42
|
-
self._default_model_base_url = default_model_base_url
|
|
43
|
-
self._default_model_api_key = default_model_api_key
|
|
44
|
-
self._default_small_model_name = default_small_model_name
|
|
45
|
-
self._default_small_model_base_url = default_small_model_base_url
|
|
46
|
-
self._default_small_model_api_key = default_small_model_api_key
|
|
47
|
-
self._default_persona = default_persona
|
|
48
|
-
self._default_system_prompt = default_system_prompt
|
|
49
|
-
self._default_interactive_system_prompt = default_interactive_system_prompt
|
|
50
|
-
self._default_special_instruction_prompt = default_special_instruction_prompt
|
|
51
|
-
self._default_summarization_prompt = default_summarization_prompt
|
|
52
|
-
self._default_summarize_history = default_summarize_history
|
|
53
|
-
self._default_history_summarization_token_threshold = (
|
|
54
|
-
default_history_summarization_token_threshold
|
|
55
|
-
)
|
|
56
|
-
self._default_workflows = default_workflows
|
|
57
|
-
self._default_model = default_model
|
|
58
|
-
self._default_model_settings = default_model_settings
|
|
59
|
-
self._default_model_provider = default_model_provider
|
|
60
|
-
self._default_small_model = default_small_model
|
|
61
|
-
self._default_small_model_settings = default_small_model_settings
|
|
62
|
-
self._default_small_model_provider = default_small_model_provider
|
|
63
|
-
self._default_yolo_mode = default_yolo_mode
|
|
64
|
-
self._default_current_weather_tool = default_current_weather_tool
|
|
65
|
-
self._default_current_location_tool = default_current_location_tool
|
|
66
|
-
self._default_search_internet_tool = default_search_internet_tool
|
|
67
|
-
|
|
68
|
-
def _get_internal_default_prompt(self, name: str) -> str:
|
|
69
|
-
if name not in self.__internal_default_prompt:
|
|
70
|
-
file_path = os.path.join(
|
|
71
|
-
os.path.dirname(__file__), "default_prompt", f"{name}.md"
|
|
72
|
-
)
|
|
73
|
-
with open(file_path, "r") as f:
|
|
74
|
-
self.__internal_default_prompt[name] = f.read().strip()
|
|
75
|
-
return self.__internal_default_prompt[name]
|
|
76
|
-
|
|
77
|
-
def _get_property(
|
|
78
|
-
self,
|
|
79
|
-
instance_var: Any,
|
|
80
|
-
config_var: Any,
|
|
81
|
-
default_func: Callable[[], Any],
|
|
82
|
-
) -> Any:
|
|
83
|
-
if instance_var is not None:
|
|
84
|
-
return instance_var
|
|
85
|
-
if config_var is not None:
|
|
86
|
-
return config_var
|
|
87
|
-
return default_func()
|
|
88
|
-
|
|
89
|
-
@property
|
|
90
|
-
def default_model_name(self) -> str | None:
|
|
91
|
-
return self._get_property(self._default_model_name, CFG.LLM_MODEL, lambda: None)
|
|
92
|
-
|
|
93
|
-
@property
|
|
94
|
-
def default_model_base_url(self) -> str | None:
|
|
95
|
-
return self._get_property(
|
|
96
|
-
self._default_model_base_url, CFG.LLM_BASE_URL, lambda: None
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
@property
|
|
100
|
-
def default_model_api_key(self) -> str | None:
|
|
101
|
-
return self._get_property(
|
|
102
|
-
self._default_model_api_key, CFG.LLM_API_KEY, lambda: None
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
@property
|
|
106
|
-
def default_model_settings(self) -> "ModelSettings | None":
|
|
107
|
-
return self._get_property(self._default_model_settings, None, lambda: None)
|
|
108
|
-
|
|
109
|
-
@property
|
|
110
|
-
def default_model_provider(self) -> "Provider | str":
|
|
111
|
-
if self._default_model_provider is not None:
|
|
112
|
-
return self._default_model_provider
|
|
113
|
-
if self.default_model_base_url is None and self.default_model_api_key is None:
|
|
114
|
-
return "openai"
|
|
115
|
-
from pydantic_ai.providers.openai import OpenAIProvider
|
|
116
|
-
|
|
117
|
-
return OpenAIProvider(
|
|
118
|
-
base_url=self.default_model_base_url, api_key=self.default_model_api_key
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
@property
|
|
122
|
-
def default_small_model_name(self) -> str | None:
|
|
123
|
-
return self._get_property(
|
|
124
|
-
self._default_small_model_name,
|
|
125
|
-
CFG.LLM_MODEL_SMALL,
|
|
126
|
-
lambda: self.default_model_name,
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
@property
|
|
130
|
-
def default_small_model_base_url(self) -> str | None:
|
|
131
|
-
return self._get_property(
|
|
132
|
-
self._default_small_model_base_url,
|
|
133
|
-
CFG.LLM_BASE_URL_SMALL,
|
|
134
|
-
lambda: self.default_model_base_url,
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
@property
|
|
138
|
-
def default_small_model_api_key(self) -> str | None:
|
|
139
|
-
return self._get_property(
|
|
140
|
-
self._default_small_model_api_key,
|
|
141
|
-
CFG.LLM_API_KEY_SMALL,
|
|
142
|
-
lambda: self.default_model_api_key,
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
@property
|
|
146
|
-
def default_small_model_settings(self) -> "ModelSettings | None":
|
|
147
|
-
return self._get_property(
|
|
148
|
-
self._default_small_model_settings,
|
|
149
|
-
None,
|
|
150
|
-
lambda: self.default_model_settings,
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
@property
|
|
154
|
-
def default_small_model_provider(self) -> "Provider | str":
|
|
155
|
-
if self._default_small_model_provider is not None:
|
|
156
|
-
return self._default_small_model_provider
|
|
157
|
-
if (
|
|
158
|
-
self.default_small_model_base_url is None
|
|
159
|
-
and self.default_small_model_api_key is None
|
|
160
|
-
):
|
|
161
|
-
return self.default_model_provider
|
|
162
|
-
from pydantic_ai.providers.openai import OpenAIProvider
|
|
163
|
-
|
|
164
|
-
return OpenAIProvider(
|
|
165
|
-
base_url=self.default_small_model_base_url,
|
|
166
|
-
api_key=self.default_small_model_api_key,
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
@property
|
|
170
|
-
def default_system_prompt(self) -> str:
|
|
171
|
-
return self._get_property(
|
|
172
|
-
self._default_system_prompt,
|
|
173
|
-
CFG.LLM_SYSTEM_PROMPT,
|
|
174
|
-
lambda: self._get_internal_default_prompt("system_prompt"),
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
@property
|
|
178
|
-
def default_interactive_system_prompt(self) -> str:
|
|
179
|
-
return self._get_property(
|
|
180
|
-
self._default_interactive_system_prompt,
|
|
181
|
-
CFG.LLM_INTERACTIVE_SYSTEM_PROMPT,
|
|
182
|
-
lambda: self._get_internal_default_prompt("interactive_system_prompt"),
|
|
183
|
-
)
|
|
184
|
-
|
|
185
|
-
@property
|
|
186
|
-
def default_persona(self) -> str:
|
|
187
|
-
return self._get_property(
|
|
188
|
-
self._default_persona,
|
|
189
|
-
CFG.LLM_PERSONA,
|
|
190
|
-
lambda: self._get_internal_default_prompt("persona"),
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
@property
|
|
194
|
-
def default_workflows(self) -> list[str]:
|
|
195
|
-
return self._get_property(
|
|
196
|
-
self._default_workflows, CFG.LLM_WORKFLOWS, lambda: []
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
@property
|
|
200
|
-
def default_special_instruction_prompt(self) -> str:
|
|
201
|
-
return self._get_property(
|
|
202
|
-
self._default_special_instruction_prompt,
|
|
203
|
-
CFG.LLM_SPECIAL_INSTRUCTION_PROMPT,
|
|
204
|
-
lambda: "",
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
@property
|
|
208
|
-
def default_summarization_prompt(self) -> str:
|
|
209
|
-
return self._get_property(
|
|
210
|
-
self._default_summarization_prompt,
|
|
211
|
-
CFG.LLM_SUMMARIZATION_PROMPT,
|
|
212
|
-
lambda: self._get_internal_default_prompt("summarization_prompt"),
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
@property
|
|
216
|
-
def default_model(self) -> "Model | str":
|
|
217
|
-
if self._default_model is not None:
|
|
218
|
-
return self._default_model
|
|
219
|
-
model_name = self.default_model_name
|
|
220
|
-
if model_name is None:
|
|
221
|
-
return "openai:gpt-4o"
|
|
222
|
-
from pydantic_ai.models.openai import OpenAIChatModel
|
|
223
|
-
|
|
224
|
-
return OpenAIChatModel(
|
|
225
|
-
model_name=model_name,
|
|
226
|
-
provider=self.default_model_provider,
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
@property
|
|
230
|
-
def default_small_model(self) -> "Model | str":
|
|
231
|
-
if self._default_small_model is not None:
|
|
232
|
-
return self._default_small_model
|
|
233
|
-
model_name = self.default_small_model_name
|
|
234
|
-
if model_name is None:
|
|
235
|
-
return "openai:gpt-4o"
|
|
236
|
-
return self.default_model
|
|
237
|
-
|
|
238
|
-
@property
|
|
239
|
-
def default_summarize_history(self) -> bool:
|
|
240
|
-
return self._get_property(
|
|
241
|
-
self._default_summarize_history, CFG.LLM_SUMMARIZE_HISTORY, lambda: False
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
@property
|
|
245
|
-
def default_history_summarization_token_threshold(self) -> int:
|
|
246
|
-
return self._get_property(
|
|
247
|
-
self._default_history_summarization_token_threshold,
|
|
248
|
-
CFG.LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD,
|
|
249
|
-
lambda: 1000,
|
|
250
|
-
)
|
|
251
|
-
|
|
252
|
-
@property
|
|
253
|
-
def default_yolo_mode(self) -> bool | list[str]:
|
|
254
|
-
return self._get_property(
|
|
255
|
-
self._default_yolo_mode, CFG.LLM_YOLO_MODE, lambda: False
|
|
256
|
-
)
|
|
257
|
-
|
|
258
|
-
@property
|
|
259
|
-
def default_current_weather_tool(self) -> Callable | None:
|
|
260
|
-
return self._default_current_weather_tool
|
|
261
|
-
|
|
262
|
-
@property
|
|
263
|
-
def default_current_location_tool(self) -> Callable | None:
|
|
264
|
-
return self._default_current_location_tool
|
|
265
|
-
|
|
266
|
-
@property
|
|
267
|
-
def default_search_internet_tool(self) -> Callable | None:
|
|
268
|
-
return self._default_search_internet_tool
|
|
269
|
-
|
|
270
|
-
def set_default_persona(self, persona: str):
|
|
271
|
-
self._default_persona = persona
|
|
272
|
-
|
|
273
|
-
def set_default_system_prompt(self, system_prompt: str):
|
|
274
|
-
self._default_system_prompt = system_prompt
|
|
275
|
-
|
|
276
|
-
def set_default_interactive_system_prompt(self, interactive_system_prompt: str):
|
|
277
|
-
self._default_interactive_system_prompt = interactive_system_prompt
|
|
278
|
-
|
|
279
|
-
def set_default_special_instruction_prompt(self, special_instruction_prompt: str):
|
|
280
|
-
self._default_special_instruction_prompt = special_instruction_prompt
|
|
281
|
-
|
|
282
|
-
def set_default_workflows(self, workflows: list[str]):
|
|
283
|
-
self._default_workflows = workflows
|
|
284
|
-
|
|
285
|
-
def add_default_workflow(self, workflow: str):
|
|
286
|
-
if self._default_workflows is None:
|
|
287
|
-
self._default_workflows = []
|
|
288
|
-
self._default_workflows.append(workflow)
|
|
289
|
-
|
|
290
|
-
def remove_default_workflow(self, workflow: str):
|
|
291
|
-
if self._default_workflows is None:
|
|
292
|
-
self._default_workflows = []
|
|
293
|
-
self._default_workflows.remove(workflow)
|
|
294
|
-
|
|
295
|
-
def set_default_summarization_prompt(self, summarization_prompt: str):
|
|
296
|
-
self._default_summarization_prompt = summarization_prompt
|
|
297
|
-
|
|
298
|
-
def set_default_model_name(self, model_name: str):
|
|
299
|
-
self._default_model_name = model_name
|
|
300
|
-
|
|
301
|
-
def set_default_model_api_key(self, model_api_key: str):
|
|
302
|
-
self._default_model_api_key = model_api_key
|
|
303
|
-
|
|
304
|
-
def set_default_model_base_url(self, model_base_url: str):
|
|
305
|
-
self._default_model_base_url = model_base_url
|
|
306
|
-
|
|
307
|
-
def set_default_model_provider(self, provider: "Provider | str"):
|
|
308
|
-
self._default_model_provider = provider
|
|
309
|
-
|
|
310
|
-
def set_default_model(self, model: "Model | str"):
|
|
311
|
-
self._default_model = model
|
|
312
|
-
|
|
313
|
-
def set_default_summarize_history(self, summarize_history: bool):
|
|
314
|
-
self._default_summarize_history = summarize_history
|
|
315
|
-
|
|
316
|
-
def set_default_history_summarization_token_threshold(
|
|
317
|
-
self, history_summarization_token_threshold: int
|
|
318
|
-
):
|
|
319
|
-
self._default_history_summarization_token_threshold = (
|
|
320
|
-
history_summarization_token_threshold
|
|
321
|
-
)
|
|
322
|
-
|
|
323
|
-
def set_default_model_settings(self, model_settings: "ModelSettings"):
|
|
324
|
-
self._default_model_settings = model_settings
|
|
325
|
-
|
|
326
|
-
def set_default_yolo_mode(self, yolo_mode: bool | list[str]):
|
|
327
|
-
self._default_yolo_mode = yolo_mode
|
|
328
|
-
|
|
329
|
-
def set_default_current_weather_tool(self, tool: Callable):
|
|
330
|
-
self._default_current_weather_tool = tool
|
|
331
|
-
|
|
332
|
-
def set_default_current_location_tool(self, tool: Callable):
|
|
333
|
-
self._default_current_location_tool = tool
|
|
334
|
-
|
|
335
|
-
def set_default_search_internet_tool(self, tool: Callable):
|
|
336
|
-
self._default_search_internet_tool = tool
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
llm_config = LLMConfig()
|
zrb/config/llm_context/config.py
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
from zrb.config.config import CFG
|
|
4
|
-
from zrb.config.llm_context.config_parser import markdown_to_dict
|
|
5
|
-
from zrb.config.llm_context.workflow import LLMWorkflow
|
|
6
|
-
from zrb.util.markdown import demote_markdown_headers
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class LLMContextConfig:
|
|
10
|
-
"""High-level API for interacting with cascaded configurations."""
|
|
11
|
-
|
|
12
|
-
def write_note(
|
|
13
|
-
self,
|
|
14
|
-
content: str,
|
|
15
|
-
context_path: str | None = None,
|
|
16
|
-
cwd: str | None = None,
|
|
17
|
-
):
|
|
18
|
-
"""Writes content to a note block in the user's home configuration file."""
|
|
19
|
-
if cwd is None:
|
|
20
|
-
cwd = os.getcwd()
|
|
21
|
-
if context_path is None:
|
|
22
|
-
context_path = cwd
|
|
23
|
-
config_file = self._get_home_config_file()
|
|
24
|
-
sections = {}
|
|
25
|
-
if os.path.exists(config_file):
|
|
26
|
-
sections = self._parse_config(config_file)
|
|
27
|
-
abs_context_path = os.path.abspath(os.path.join(cwd, context_path))
|
|
28
|
-
found_key = None
|
|
29
|
-
for key in sections.keys():
|
|
30
|
-
if not key.startswith("Note:"):
|
|
31
|
-
continue
|
|
32
|
-
context_path_str = key[len("Note:") :].strip()
|
|
33
|
-
abs_key_path = self._normalize_context_path(
|
|
34
|
-
context_path_str,
|
|
35
|
-
os.path.dirname(config_file),
|
|
36
|
-
)
|
|
37
|
-
if abs_key_path == abs_context_path:
|
|
38
|
-
found_key = key
|
|
39
|
-
break
|
|
40
|
-
if found_key:
|
|
41
|
-
sections[found_key] = content
|
|
42
|
-
else:
|
|
43
|
-
config_dir = os.path.dirname(config_file)
|
|
44
|
-
formatted_path = self._format_context_path_for_writing(
|
|
45
|
-
abs_context_path,
|
|
46
|
-
config_dir,
|
|
47
|
-
)
|
|
48
|
-
new_key = f"Note: {formatted_path}"
|
|
49
|
-
sections[new_key] = content
|
|
50
|
-
# Serialize back to markdown
|
|
51
|
-
new_file_content = ""
|
|
52
|
-
for key, value in sections.items():
|
|
53
|
-
new_file_content += f"# {key}\n{demote_markdown_headers(value)}\n\n"
|
|
54
|
-
with open(config_file, "w") as f:
|
|
55
|
-
f.write(new_file_content)
|
|
56
|
-
|
|
57
|
-
def get_notes(self, cwd: str | None = None) -> dict[str, str]:
|
|
58
|
-
"""Gathers all notes for a given path."""
|
|
59
|
-
if cwd is None:
|
|
60
|
-
cwd = os.getcwd()
|
|
61
|
-
config_file = self._get_home_config_file()
|
|
62
|
-
if not os.path.exists(config_file):
|
|
63
|
-
return {}
|
|
64
|
-
config_dir = os.path.dirname(config_file)
|
|
65
|
-
sections = self._parse_config(config_file)
|
|
66
|
-
notes: dict[str, str] = {}
|
|
67
|
-
for key, value in sections.items():
|
|
68
|
-
if key.lower().startswith("note:"):
|
|
69
|
-
context_path_str = key[len("note:") :].strip()
|
|
70
|
-
abs_context_path = self._normalize_context_path(
|
|
71
|
-
context_path_str,
|
|
72
|
-
config_dir,
|
|
73
|
-
)
|
|
74
|
-
# A context is relevant if its path is an ancestor of cwd
|
|
75
|
-
if os.path.commonpath([cwd, abs_context_path]) == abs_context_path:
|
|
76
|
-
notes[abs_context_path] = value
|
|
77
|
-
return notes
|
|
78
|
-
|
|
79
|
-
def get_workflows(self, cwd: str | None = None) -> dict[str, LLMWorkflow]:
|
|
80
|
-
"""Gathers all relevant workflows for a given path."""
|
|
81
|
-
if cwd is None:
|
|
82
|
-
cwd = os.getcwd()
|
|
83
|
-
all_sections = self._get_all_sections(cwd)
|
|
84
|
-
workflows: dict[str, LLMWorkflow] = {}
|
|
85
|
-
# Iterate from closest to farthest
|
|
86
|
-
for config_dir, sections in all_sections:
|
|
87
|
-
for key, value in sections.items():
|
|
88
|
-
if key.lower().startswith("workflow:"):
|
|
89
|
-
workflow_name = key[len("workflow:") :].strip().lower()
|
|
90
|
-
# First one found wins
|
|
91
|
-
if workflow_name not in workflows:
|
|
92
|
-
workflows[workflow_name] = LLMWorkflow(
|
|
93
|
-
name=workflow_name,
|
|
94
|
-
content=value,
|
|
95
|
-
path=config_dir,
|
|
96
|
-
)
|
|
97
|
-
return workflows
|
|
98
|
-
|
|
99
|
-
def _format_context_path_for_writing(
|
|
100
|
-
self,
|
|
101
|
-
path_to_write: str,
|
|
102
|
-
relative_to_dir: str,
|
|
103
|
-
) -> str:
|
|
104
|
-
"""Formats a path for writing into a context file key."""
|
|
105
|
-
home_dir = os.path.expanduser("~")
|
|
106
|
-
abs_path_to_write = os.path.abspath(
|
|
107
|
-
os.path.join(relative_to_dir, path_to_write)
|
|
108
|
-
)
|
|
109
|
-
abs_relative_to_dir = os.path.abspath(relative_to_dir)
|
|
110
|
-
# Rule 1: Inside relative_to_dir
|
|
111
|
-
if abs_path_to_write.startswith(abs_relative_to_dir):
|
|
112
|
-
if abs_path_to_write == abs_relative_to_dir:
|
|
113
|
-
return "."
|
|
114
|
-
return os.path.relpath(abs_path_to_write, abs_relative_to_dir)
|
|
115
|
-
# Rule 2: Inside Home
|
|
116
|
-
if abs_path_to_write.startswith(home_dir):
|
|
117
|
-
if abs_path_to_write == home_dir:
|
|
118
|
-
return "~"
|
|
119
|
-
return os.path.join("~", os.path.relpath(abs_path_to_write, home_dir))
|
|
120
|
-
# Rule 3: Absolute
|
|
121
|
-
return abs_path_to_write
|
|
122
|
-
|
|
123
|
-
def _find_config_files(self, cwd: str) -> list[str]:
|
|
124
|
-
configs = []
|
|
125
|
-
current_dir = cwd
|
|
126
|
-
home_dir = os.path.expanduser("~")
|
|
127
|
-
while True:
|
|
128
|
-
config_path = os.path.join(current_dir, CFG.LLM_CONTEXT_FILE)
|
|
129
|
-
if os.path.exists(config_path):
|
|
130
|
-
configs.append(config_path)
|
|
131
|
-
if current_dir == home_dir or current_dir == "/":
|
|
132
|
-
break
|
|
133
|
-
current_dir = os.path.dirname(current_dir)
|
|
134
|
-
return configs
|
|
135
|
-
|
|
136
|
-
def _get_home_config_file(self) -> str:
|
|
137
|
-
home_dir = os.path.expanduser("~")
|
|
138
|
-
return os.path.join(home_dir, CFG.LLM_CONTEXT_FILE)
|
|
139
|
-
|
|
140
|
-
def _parse_config(self, file_path: str) -> dict[str, str]:
|
|
141
|
-
with open(file_path, "r") as f:
|
|
142
|
-
content = f.read()
|
|
143
|
-
return markdown_to_dict(content)
|
|
144
|
-
|
|
145
|
-
def _get_all_sections(self, cwd: str) -> list[tuple[str, dict[str, str]]]:
|
|
146
|
-
config_files = self._find_config_files(cwd)
|
|
147
|
-
all_sections = []
|
|
148
|
-
for config_file in config_files:
|
|
149
|
-
config_dir = os.path.dirname(config_file)
|
|
150
|
-
sections = self._parse_config(config_file)
|
|
151
|
-
all_sections.append((config_dir, sections))
|
|
152
|
-
return all_sections
|
|
153
|
-
|
|
154
|
-
def _normalize_context_path(
|
|
155
|
-
self,
|
|
156
|
-
path_str: str,
|
|
157
|
-
relative_to_dir: str,
|
|
158
|
-
) -> str:
|
|
159
|
-
"""Normalizes a context path string to an absolute path."""
|
|
160
|
-
expanded_path = os.path.expanduser(path_str)
|
|
161
|
-
if os.path.isabs(expanded_path):
|
|
162
|
-
return os.path.abspath(expanded_path)
|
|
163
|
-
return os.path.abspath(os.path.join(relative_to_dir, expanded_path))
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
llm_context_config = LLMContextConfig()
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
|
|
3
|
-
from zrb.util.markdown import promote_markdown_headers
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def markdown_to_dict(markdown: str) -> dict[str, str]:
|
|
7
|
-
sections: dict[str, str] = {}
|
|
8
|
-
current_title = ""
|
|
9
|
-
current_content: list[str] = []
|
|
10
|
-
fence_stack: list[str] = []
|
|
11
|
-
fence_pattern = re.compile(r"^([`~]{3,})(.*)$")
|
|
12
|
-
h1_pattern = re.compile(r"^# (.+)$")
|
|
13
|
-
for line in markdown.splitlines():
|
|
14
|
-
# Detect code fence open/close
|
|
15
|
-
fence_match = fence_pattern.match(line.strip())
|
|
16
|
-
if fence_match:
|
|
17
|
-
fence = fence_match.group(1)
|
|
18
|
-
if fence_stack and fence_stack[-1] == fence:
|
|
19
|
-
fence_stack.pop() # close current fence
|
|
20
|
-
else:
|
|
21
|
-
fence_stack.append(fence) # open new fence
|
|
22
|
-
# Only parse H1 when not inside a code fence
|
|
23
|
-
if not fence_stack:
|
|
24
|
-
h1_match = h1_pattern.match(line)
|
|
25
|
-
if h1_match:
|
|
26
|
-
# Save previous section
|
|
27
|
-
if current_title:
|
|
28
|
-
sections[current_title] = "\n".join(current_content).strip()
|
|
29
|
-
# Start new section
|
|
30
|
-
current_title = h1_match.group(1).strip()
|
|
31
|
-
current_content = []
|
|
32
|
-
continue
|
|
33
|
-
current_content.append(line)
|
|
34
|
-
# Save final section
|
|
35
|
-
if current_title:
|
|
36
|
-
sections[current_title] = "\n".join(current_content).strip()
|
|
37
|
-
return {
|
|
38
|
-
header: promote_markdown_headers(content)
|
|
39
|
-
for header, content in sections.items()
|
|
40
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
class LLMWorkflow:
|
|
2
|
-
def __init__(
|
|
3
|
-
self, name: str, path: str, content: str, description: str | None = None
|
|
4
|
-
):
|
|
5
|
-
self._name = name
|
|
6
|
-
self._path = path
|
|
7
|
-
|
|
8
|
-
# Extract YAML metadata and clean content
|
|
9
|
-
(
|
|
10
|
-
extracted_description,
|
|
11
|
-
cleaned_content,
|
|
12
|
-
) = self._extract_yaml_metadata_and_clean_content(content)
|
|
13
|
-
self._content = cleaned_content
|
|
14
|
-
|
|
15
|
-
# Use provided description or extracted one
|
|
16
|
-
self._description = (
|
|
17
|
-
description if description is not None else extracted_description
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
def _extract_yaml_metadata_and_clean_content(
|
|
21
|
-
self, content: str
|
|
22
|
-
) -> tuple[str | None, str]:
|
|
23
|
-
"""Extract YAML metadata and clean content.
|
|
24
|
-
|
|
25
|
-
Looks for YAML metadata between --- lines, extracts the 'description' field,
|
|
26
|
-
and returns the content without the YAML metadata.
|
|
27
|
-
"""
|
|
28
|
-
import re
|
|
29
|
-
|
|
30
|
-
import yaml
|
|
31
|
-
|
|
32
|
-
# Pattern to match YAML metadata between --- delimiters
|
|
33
|
-
yaml_pattern = r"^---\s*\n(.*?)\n---\s*\n"
|
|
34
|
-
match = re.search(yaml_pattern, content, re.DOTALL | re.MULTILINE)
|
|
35
|
-
|
|
36
|
-
if match:
|
|
37
|
-
yaml_content = match.group(1)
|
|
38
|
-
try:
|
|
39
|
-
metadata = yaml.safe_load(yaml_content)
|
|
40
|
-
description = (
|
|
41
|
-
metadata.get("description") if isinstance(metadata, dict) else None
|
|
42
|
-
)
|
|
43
|
-
# Remove the YAML metadata from content
|
|
44
|
-
cleaned_content = re.sub(
|
|
45
|
-
yaml_pattern, "", content, count=1, flags=re.DOTALL | re.MULTILINE
|
|
46
|
-
)
|
|
47
|
-
return description, cleaned_content.strip()
|
|
48
|
-
except yaml.YAMLError:
|
|
49
|
-
# If YAML parsing fails, return original content
|
|
50
|
-
pass
|
|
51
|
-
|
|
52
|
-
# No YAML metadata found, return original content
|
|
53
|
-
return None, content
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
def name(self) -> str:
|
|
57
|
-
return self._name
|
|
58
|
-
|
|
59
|
-
@property
|
|
60
|
-
def path(self) -> str:
|
|
61
|
-
return self._path
|
|
62
|
-
|
|
63
|
-
@property
|
|
64
|
-
def content(self) -> str:
|
|
65
|
-
return self._content
|
|
66
|
-
|
|
67
|
-
@property
|
|
68
|
-
def description(self) -> str:
|
|
69
|
-
if self._description is not None:
|
|
70
|
-
return self._description
|
|
71
|
-
if len(self._content) > 1000:
|
|
72
|
-
non_empty_lines = [
|
|
73
|
-
line for line in self._content.split("\n") if line.strip() != ""
|
|
74
|
-
]
|
|
75
|
-
first_non_empty_line = (
|
|
76
|
-
non_empty_lines[0] if len(non_empty_lines) > 0 else ""
|
|
77
|
-
)
|
|
78
|
-
if len(first_non_empty_line) > 200:
|
|
79
|
-
return first_non_empty_line[:200] + "... (more)"
|
|
80
|
-
return first_non_empty_line
|
|
81
|
-
return self._content
|