zrb 1.15.3__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 -133
- zrb/attr/type.py +10 -7
- zrb/builtin/__init__.py +55 -1
- zrb/builtin/git.py +12 -1
- zrb/builtin/group.py +31 -15
- zrb/builtin/llm/chat.py +147 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +7 -7
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +5 -5
- zrb/builtin/project/add/fastapp/fastapp_util.py +1 -1
- zrb/builtin/searxng/config/settings.yml +5671 -0
- zrb/builtin/searxng/start.py +21 -0
- zrb/builtin/shell/autocomplete/bash.py +4 -3
- zrb/builtin/shell/autocomplete/zsh.py +4 -3
- zrb/callback/callback.py +8 -1
- zrb/cmd/cmd_result.py +2 -1
- zrb/config/config.py +555 -169
- zrb/config/helper.py +84 -0
- zrb/config/web_auth_config.py +50 -35
- zrb/context/any_shared_context.py +20 -3
- zrb/context/context.py +39 -5
- zrb/context/print_fn.py +13 -0
- zrb/context/shared_context.py +17 -8
- zrb/group/any_group.py +3 -3
- zrb/group/group.py +3 -3
- zrb/input/any_input.py +5 -1
- zrb/input/base_input.py +18 -6
- zrb/input/option_input.py +41 -1
- zrb/input/text_input.py +7 -24
- 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/file_extractor.md +112 -0
- zrb/llm/prompt/markdown/mandate.md +23 -0
- zrb/llm/prompt/markdown/persona.md +3 -0
- zrb/llm/prompt/markdown/repo_extractor.md +112 -0
- zrb/llm/prompt/markdown/repo_summarizer.md +29 -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 +33 -37
- 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/runner/cli.py +21 -20
- zrb/runner/common_util.py +24 -19
- zrb/runner/web_route/task_input_api_route.py +5 -5
- zrb/runner/web_util/user.py +7 -3
- zrb/session/any_session.py +12 -9
- zrb/session/session.py +38 -17
- zrb/task/any_task.py +24 -3
- zrb/task/base/context.py +42 -22
- zrb/task/base/execution.py +67 -55
- zrb/task/base/lifecycle.py +14 -7
- zrb/task/base/monitoring.py +12 -7
- zrb/task/base_task.py +113 -50
- zrb/task/base_trigger.py +16 -6
- zrb/task/cmd_task.py +6 -0
- zrb/task/http_check.py +11 -5
- zrb/task/make_task.py +5 -3
- zrb/task/rsync_task.py +30 -10
- zrb/task/scaffolder.py +7 -4
- zrb/task/scheduler.py +7 -4
- 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/attr.py +54 -39
- zrb/util/cli/markdown.py +32 -0
- zrb/util/cli/text.py +30 -0
- zrb/util/cmd/command.py +33 -10
- zrb/util/file.py +61 -33
- zrb/util/git.py +2 -2
- zrb/util/{llm/prompt.py → markdown.py} +2 -3
- zrb/util/match.py +78 -0
- zrb/util/run.py +3 -3
- zrb/util/string/conversion.py +1 -1
- zrb/util/truncate.py +23 -0
- zrb/util/yaml.py +204 -0
- zrb/xcom/xcom.py +10 -0
- {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/METADATA +41 -27
- {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/RECORD +129 -131
- {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/WHEEL +1 -1
- zrb/attr/__init__.py +0 -0
- zrb/builtin/llm/chat_session.py +0 -311
- zrb/builtin/llm/history.py +0 -71
- zrb/builtin/llm/input.py +0 -27
- zrb/builtin/llm/llm_ask.py +0 -187
- zrb/builtin/llm/previous-session.js +0 -21
- zrb/builtin/llm/tool/__init__.py +0 -0
- zrb/builtin/llm/tool/api.py +0 -71
- zrb/builtin/llm/tool/cli.py +0 -38
- zrb/builtin/llm/tool/code.py +0 -254
- zrb/builtin/llm/tool/file.py +0 -626
- zrb/builtin/llm/tool/sub_agent.py +0 -137
- zrb/builtin/llm/tool/web.py +0 -195
- 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/file_extractor_system_prompt.md +0 -12
- zrb/config/default_prompt/interactive_system_prompt.md +0 -35
- zrb/config/default_prompt/persona.md +0 -1
- zrb/config/default_prompt/repo_extractor_system_prompt.md +0 -112
- zrb/config/default_prompt/repo_summarizer_system_prompt.md +0 -10
- zrb/config/default_prompt/summarization_prompt.md +0 -16
- zrb/config/default_prompt/system_prompt.md +0 -32
- zrb/config/llm_config.py +0 -243
- zrb/config/llm_context/config.py +0 -129
- zrb/config/llm_context/config_parser.py +0 -46
- zrb/config/llm_rate_limitter.py +0 -137
- 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 -243
- zrb/task/llm/config.py +0 -103
- zrb/task/llm/conversation_history.py +0 -128
- zrb/task/llm/conversation_history_model.py +0 -242
- zrb/task/llm/default_workflow/coding.md +0 -24
- zrb/task/llm/default_workflow/copywriting.md +0 -17
- zrb/task/llm/default_workflow/researching.md +0 -18
- zrb/task/llm/error.py +0 -95
- zrb/task/llm/history_summarization.py +0 -216
- zrb/task/llm/print_node.py +0 -101
- zrb/task/llm/prompt.py +0 -325
- zrb/task/llm/tool_wrapper.py +0 -220
- zrb/task/llm/typing.py +0 -3
- zrb/task/llm_task.py +0 -341
- 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-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/entry_points.txt +0 -0
zrb/task/llm/agent.py
DELETED
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from collections.abc import Callable
|
|
3
|
-
from typing import TYPE_CHECKING, Any
|
|
4
|
-
|
|
5
|
-
from zrb.config.llm_rate_limitter import LLMRateLimiter, llm_rate_limitter
|
|
6
|
-
from zrb.context.any_context import AnyContext
|
|
7
|
-
from zrb.context.any_shared_context import AnySharedContext
|
|
8
|
-
from zrb.task.llm.error import extract_api_error_details
|
|
9
|
-
from zrb.task.llm.print_node import print_node
|
|
10
|
-
from zrb.task.llm.tool_wrapper import wrap_func, wrap_tool
|
|
11
|
-
from zrb.task.llm.typing import ListOfDict
|
|
12
|
-
|
|
13
|
-
if TYPE_CHECKING:
|
|
14
|
-
from pydantic_ai import Agent, Tool
|
|
15
|
-
from pydantic_ai.agent import AgentRun
|
|
16
|
-
from pydantic_ai.messages import UserContent
|
|
17
|
-
from pydantic_ai.models import Model
|
|
18
|
-
from pydantic_ai.settings import ModelSettings
|
|
19
|
-
from pydantic_ai.toolsets import AbstractToolset
|
|
20
|
-
|
|
21
|
-
ToolOrCallable = Tool | Callable
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def create_agent_instance(
|
|
25
|
-
ctx: AnyContext,
|
|
26
|
-
model: "str | Model",
|
|
27
|
-
system_prompt: str = "",
|
|
28
|
-
model_settings: "ModelSettings | None" = None,
|
|
29
|
-
tools: "list[ToolOrCallable]" = [],
|
|
30
|
-
toolsets: list["AbstractToolset[Agent]"] = [],
|
|
31
|
-
retries: int = 3,
|
|
32
|
-
is_yolo_mode: bool | None = None,
|
|
33
|
-
) -> "Agent":
|
|
34
|
-
"""Creates a new Agent instance with configured tools and servers."""
|
|
35
|
-
from pydantic_ai import Agent, Tool
|
|
36
|
-
from pydantic_ai.tools import GenerateToolJsonSchema
|
|
37
|
-
|
|
38
|
-
if is_yolo_mode is None:
|
|
39
|
-
is_yolo_mode = False
|
|
40
|
-
# Normalize tools
|
|
41
|
-
tool_list = []
|
|
42
|
-
for tool_or_callable in tools:
|
|
43
|
-
if isinstance(tool_or_callable, Tool):
|
|
44
|
-
tool_list.append(tool_or_callable)
|
|
45
|
-
# Update tool's function
|
|
46
|
-
tool = tool_or_callable
|
|
47
|
-
tool_list.append(
|
|
48
|
-
Tool(
|
|
49
|
-
function=wrap_func(tool.function, ctx, is_yolo_mode),
|
|
50
|
-
takes_ctx=tool.takes_ctx,
|
|
51
|
-
max_retries=tool.max_retries,
|
|
52
|
-
name=tool.name,
|
|
53
|
-
description=tool.description,
|
|
54
|
-
prepare=tool.prepare,
|
|
55
|
-
docstring_format=tool.docstring_format,
|
|
56
|
-
require_parameter_descriptions=tool.require_parameter_descriptions,
|
|
57
|
-
schema_generator=GenerateToolJsonSchema,
|
|
58
|
-
strict=tool.strict,
|
|
59
|
-
)
|
|
60
|
-
)
|
|
61
|
-
else:
|
|
62
|
-
# Turn function into tool
|
|
63
|
-
tool_list.append(wrap_tool(tool_or_callable, ctx, is_yolo_mode))
|
|
64
|
-
# Return Agent
|
|
65
|
-
return Agent(
|
|
66
|
-
model=model,
|
|
67
|
-
system_prompt=system_prompt,
|
|
68
|
-
tools=tool_list,
|
|
69
|
-
toolsets=toolsets,
|
|
70
|
-
model_settings=model_settings,
|
|
71
|
-
retries=retries,
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def get_agent(
|
|
76
|
-
ctx: AnyContext,
|
|
77
|
-
agent_attr: "Agent | Callable[[AnySharedContext], Agent] | None",
|
|
78
|
-
model: "str | Model",
|
|
79
|
-
system_prompt: str,
|
|
80
|
-
model_settings: "ModelSettings | None",
|
|
81
|
-
tools_attr: (
|
|
82
|
-
"list[ToolOrCallable] | Callable[[AnySharedContext], list[ToolOrCallable]]"
|
|
83
|
-
),
|
|
84
|
-
additional_tools: "list[ToolOrCallable]",
|
|
85
|
-
toolsets_attr: "list[AbstractToolset[Agent]] | Callable[[AnySharedContext], list[AbstractToolset[Agent]]]", # noqa
|
|
86
|
-
additional_toolsets: "list[AbstractToolset[Agent]]",
|
|
87
|
-
retries: int = 3,
|
|
88
|
-
is_yolo_mode: bool | None = None,
|
|
89
|
-
) -> "Agent":
|
|
90
|
-
"""Retrieves the configured Agent instance or creates one if necessary."""
|
|
91
|
-
from pydantic_ai import Agent
|
|
92
|
-
|
|
93
|
-
# Render agent instance and return if agent_attr is already an agent
|
|
94
|
-
if isinstance(agent_attr, Agent):
|
|
95
|
-
return agent_attr
|
|
96
|
-
if callable(agent_attr):
|
|
97
|
-
agent_instance = agent_attr(ctx)
|
|
98
|
-
if not isinstance(agent_instance, Agent):
|
|
99
|
-
err_msg = (
|
|
100
|
-
"Callable agent factory did not return an Agent instance, "
|
|
101
|
-
f"got: {type(agent_instance)}"
|
|
102
|
-
)
|
|
103
|
-
raise TypeError(err_msg)
|
|
104
|
-
return agent_instance
|
|
105
|
-
# Get tools for agent
|
|
106
|
-
tools = list(tools_attr(ctx) if callable(tools_attr) else tools_attr)
|
|
107
|
-
tools.extend(additional_tools)
|
|
108
|
-
# Get Toolsets for agent
|
|
109
|
-
tool_sets = list(toolsets_attr(ctx) if callable(toolsets_attr) else toolsets_attr)
|
|
110
|
-
tool_sets.extend(additional_toolsets)
|
|
111
|
-
# If no agent provided, create one using the configuration
|
|
112
|
-
return create_agent_instance(
|
|
113
|
-
ctx=ctx,
|
|
114
|
-
model=model,
|
|
115
|
-
system_prompt=system_prompt,
|
|
116
|
-
tools=tools,
|
|
117
|
-
toolsets=tool_sets,
|
|
118
|
-
model_settings=model_settings,
|
|
119
|
-
retries=retries,
|
|
120
|
-
is_yolo_mode=is_yolo_mode,
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
async def run_agent_iteration(
|
|
125
|
-
ctx: AnyContext,
|
|
126
|
-
agent: "Agent",
|
|
127
|
-
user_prompt: str,
|
|
128
|
-
attachments: "list[UserContent] | None" = None,
|
|
129
|
-
history_list: ListOfDict | None = None,
|
|
130
|
-
rate_limitter: LLMRateLimiter | None = None,
|
|
131
|
-
max_retry: int = 2,
|
|
132
|
-
) -> "AgentRun":
|
|
133
|
-
"""
|
|
134
|
-
Runs a single iteration of the agent execution loop.
|
|
135
|
-
|
|
136
|
-
Args:
|
|
137
|
-
ctx: The task context.
|
|
138
|
-
agent: The Pydantic AI agent instance.
|
|
139
|
-
user_prompt: The user's input prompt.
|
|
140
|
-
history_list: The current conversation history.
|
|
141
|
-
|
|
142
|
-
Returns:
|
|
143
|
-
The agent run result object.
|
|
144
|
-
|
|
145
|
-
Raises:
|
|
146
|
-
Exception: If any error occurs during agent execution.
|
|
147
|
-
"""
|
|
148
|
-
if max_retry < 0:
|
|
149
|
-
raise ValueError("Max retry cannot be less than 0")
|
|
150
|
-
attempt = 0
|
|
151
|
-
while attempt < max_retry:
|
|
152
|
-
try:
|
|
153
|
-
return await _run_single_agent_iteration(
|
|
154
|
-
ctx=ctx,
|
|
155
|
-
agent=agent,
|
|
156
|
-
user_prompt=user_prompt,
|
|
157
|
-
attachments=[] if attachments is None else attachments,
|
|
158
|
-
history_list=[] if history_list is None else history_list,
|
|
159
|
-
rate_limitter=(
|
|
160
|
-
llm_rate_limitter if rate_limitter is None else rate_limitter
|
|
161
|
-
),
|
|
162
|
-
)
|
|
163
|
-
except BaseException:
|
|
164
|
-
attempt += 1
|
|
165
|
-
if attempt == max_retry:
|
|
166
|
-
raise
|
|
167
|
-
raise Exception("Max retry exceeded")
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
async def _run_single_agent_iteration(
|
|
171
|
-
ctx: AnyContext,
|
|
172
|
-
agent: "Agent",
|
|
173
|
-
user_prompt: str,
|
|
174
|
-
attachments: "list[UserContent]",
|
|
175
|
-
history_list: ListOfDict,
|
|
176
|
-
rate_limitter: LLMRateLimiter,
|
|
177
|
-
) -> "AgentRun":
|
|
178
|
-
from openai import APIError
|
|
179
|
-
from pydantic_ai.messages import ModelMessagesTypeAdapter
|
|
180
|
-
|
|
181
|
-
agent_payload = _estimate_request_payload(
|
|
182
|
-
agent, user_prompt, attachments, history_list
|
|
183
|
-
)
|
|
184
|
-
if rate_limitter:
|
|
185
|
-
await rate_limitter.throttle(agent_payload)
|
|
186
|
-
else:
|
|
187
|
-
await llm_rate_limitter.throttle(agent_payload)
|
|
188
|
-
|
|
189
|
-
user_prompt_with_attachments = [user_prompt] + attachments
|
|
190
|
-
async with agent:
|
|
191
|
-
async with agent.iter(
|
|
192
|
-
user_prompt=user_prompt_with_attachments,
|
|
193
|
-
message_history=ModelMessagesTypeAdapter.validate_python(history_list),
|
|
194
|
-
) as agent_run:
|
|
195
|
-
async for node in agent_run:
|
|
196
|
-
# Each node represents a step in the agent's execution
|
|
197
|
-
# Reference: https://ai.pydantic.dev/agents/#streaming
|
|
198
|
-
try:
|
|
199
|
-
await print_node(_get_plain_printer(ctx), agent_run, node)
|
|
200
|
-
except APIError as e:
|
|
201
|
-
# Extract detailed error information from the response
|
|
202
|
-
error_details = extract_api_error_details(e)
|
|
203
|
-
ctx.log_error(f"API Error: {error_details}")
|
|
204
|
-
raise
|
|
205
|
-
except Exception as e:
|
|
206
|
-
ctx.log_error(f"Error processing node: {str(e)}")
|
|
207
|
-
ctx.log_error(f"Error type: {type(e).__name__}")
|
|
208
|
-
raise
|
|
209
|
-
return agent_run
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
def _estimate_request_payload(
|
|
213
|
-
agent: "Agent",
|
|
214
|
-
user_prompt: str,
|
|
215
|
-
attachments: "list[UserContent]",
|
|
216
|
-
history_list: ListOfDict,
|
|
217
|
-
) -> str:
|
|
218
|
-
system_prompts = agent._system_prompts if hasattr(agent, "_system_prompts") else ()
|
|
219
|
-
return json.dumps(
|
|
220
|
-
[
|
|
221
|
-
{"role": "system", "content": "\n".join(system_prompts)},
|
|
222
|
-
*history_list,
|
|
223
|
-
{"role": "user", "content": user_prompt},
|
|
224
|
-
*[_estimate_attachment_payload(attachment) for attachment in attachments],
|
|
225
|
-
]
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
def _estimate_attachment_payload(attachment: "UserContent") -> Any:
|
|
230
|
-
if hasattr(attachment, "url"):
|
|
231
|
-
return {"role": "user", "content": attachment.url}
|
|
232
|
-
if hasattr(attachment, "data"):
|
|
233
|
-
return {"role": "user", "content": "x" * len(attachment.data)}
|
|
234
|
-
return ""
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
def _get_plain_printer(ctx: AnyContext):
|
|
238
|
-
def printer(*args, **kwargs):
|
|
239
|
-
if "plain" not in kwargs:
|
|
240
|
-
kwargs["plain"] = True
|
|
241
|
-
return ctx.print(*args, **kwargs)
|
|
242
|
-
|
|
243
|
-
return printer
|
zrb/task/llm/config.py
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING, Callable
|
|
2
|
-
|
|
3
|
-
if TYPE_CHECKING:
|
|
4
|
-
from pydantic_ai.models import Model
|
|
5
|
-
from pydantic_ai.settings import ModelSettings
|
|
6
|
-
|
|
7
|
-
from zrb.attr.type import BoolAttr, StrAttr, fstring
|
|
8
|
-
from zrb.config.llm_config import LLMConfig, llm_config
|
|
9
|
-
from zrb.context.any_context import AnyContext
|
|
10
|
-
from zrb.context.any_shared_context import AnySharedContext
|
|
11
|
-
from zrb.util.attr import get_attr, get_bool_attr
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def get_is_yolo_mode(
|
|
15
|
-
ctx: AnyContext,
|
|
16
|
-
is_yolo_mode_attr: BoolAttr | None = None,
|
|
17
|
-
render_yolo_mode: bool = True,
|
|
18
|
-
):
|
|
19
|
-
return get_bool_attr(
|
|
20
|
-
ctx,
|
|
21
|
-
is_yolo_mode_attr,
|
|
22
|
-
llm_config.default_yolo_mode,
|
|
23
|
-
auto_render=render_yolo_mode,
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def get_model_settings(
|
|
28
|
-
ctx: AnyContext,
|
|
29
|
-
model_settings_attr: (
|
|
30
|
-
"ModelSettings | Callable[[AnySharedContext], ModelSettings] | None"
|
|
31
|
-
) = None,
|
|
32
|
-
) -> "ModelSettings | None":
|
|
33
|
-
"""Gets the model settings, resolving callables if necessary."""
|
|
34
|
-
model_settings = get_attr(ctx, model_settings_attr, None, auto_render=False)
|
|
35
|
-
if model_settings is None:
|
|
36
|
-
return llm_config.default_model_settings
|
|
37
|
-
return model_settings
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def get_model_base_url(
|
|
41
|
-
ctx: AnyContext,
|
|
42
|
-
model_base_url_attr: StrAttr | None = None,
|
|
43
|
-
render_model_base_url: bool = True,
|
|
44
|
-
) -> str | None:
|
|
45
|
-
"""Gets the model base URL, rendering if configured."""
|
|
46
|
-
base_url = get_attr(
|
|
47
|
-
ctx, model_base_url_attr, None, auto_render=render_model_base_url
|
|
48
|
-
)
|
|
49
|
-
if base_url is None and llm_config.default_model_base_url is not None:
|
|
50
|
-
return llm_config.default_model_base_url
|
|
51
|
-
if isinstance(base_url, str) or base_url is None:
|
|
52
|
-
return base_url
|
|
53
|
-
raise ValueError(f"Invalid model base URL: {base_url}")
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def get_model_api_key(
|
|
57
|
-
ctx: AnyContext,
|
|
58
|
-
model_api_key_attr: StrAttr | None = None,
|
|
59
|
-
render_model_api_key: bool = True,
|
|
60
|
-
) -> str | None:
|
|
61
|
-
"""Gets the model API key, rendering if configured."""
|
|
62
|
-
api_key = get_attr(ctx, model_api_key_attr, None, auto_render=render_model_api_key)
|
|
63
|
-
if api_key is None and llm_config.default_api_key is not None:
|
|
64
|
-
return llm_config.default_model_api_key
|
|
65
|
-
if isinstance(api_key, str) or api_key is None:
|
|
66
|
-
return api_key
|
|
67
|
-
raise ValueError(f"Invalid model API key: {api_key}")
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def get_model(
|
|
71
|
-
ctx: AnyContext,
|
|
72
|
-
model_attr: "Callable[[AnySharedContext], Model | str | fstring] | Model | None",
|
|
73
|
-
render_model: bool,
|
|
74
|
-
model_base_url_attr: StrAttr | None = None,
|
|
75
|
-
render_model_base_url: bool = True,
|
|
76
|
-
model_api_key_attr: StrAttr | None = None,
|
|
77
|
-
render_model_api_key: bool = True,
|
|
78
|
-
) -> "str | Model":
|
|
79
|
-
"""Gets the model instance or name, handling defaults and configuration."""
|
|
80
|
-
from pydantic_ai.models import Model
|
|
81
|
-
|
|
82
|
-
model = get_attr(ctx, model_attr, None, auto_render=render_model)
|
|
83
|
-
if model is None:
|
|
84
|
-
return llm_config.default_model
|
|
85
|
-
if isinstance(model, str):
|
|
86
|
-
model_base_url = get_model_base_url(
|
|
87
|
-
ctx, model_base_url_attr, render_model_base_url
|
|
88
|
-
)
|
|
89
|
-
model_api_key = get_model_api_key(ctx, model_api_key_attr, render_model_api_key)
|
|
90
|
-
new_llm_config = LLMConfig(
|
|
91
|
-
default_model_name=model,
|
|
92
|
-
default_base_url=model_base_url,
|
|
93
|
-
default_api_key=model_api_key,
|
|
94
|
-
)
|
|
95
|
-
if model_base_url is None and model_api_key is None:
|
|
96
|
-
default_model_provider = llm_config.default_model_provider
|
|
97
|
-
if default_model_provider is not None:
|
|
98
|
-
new_llm_config.set_default_model_provider(default_model_provider)
|
|
99
|
-
return new_llm_config.default_model
|
|
100
|
-
# If it's already a Model instance, return it directly
|
|
101
|
-
if isinstance(model, Model):
|
|
102
|
-
return model
|
|
103
|
-
raise ValueError(f"Invalid model type resolved: {type(model)}, value: {model}")
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from collections.abc import Callable
|
|
3
|
-
from copy import deepcopy
|
|
4
|
-
from typing import Any
|
|
5
|
-
|
|
6
|
-
from zrb.attr.type import StrAttr
|
|
7
|
-
from zrb.context.any_context import AnyContext
|
|
8
|
-
from zrb.context.any_shared_context import AnySharedContext
|
|
9
|
-
from zrb.task.llm.conversation_history_model import ConversationHistory
|
|
10
|
-
from zrb.task.llm.typing import ListOfDict
|
|
11
|
-
from zrb.util.attr import get_str_attr
|
|
12
|
-
from zrb.util.file import write_file
|
|
13
|
-
from zrb.util.run import run_async
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def get_history_file(
|
|
17
|
-
ctx: AnyContext,
|
|
18
|
-
conversation_history_file_attr: StrAttr | None,
|
|
19
|
-
render_history_file: bool,
|
|
20
|
-
) -> str:
|
|
21
|
-
"""Gets the path to the conversation history file, rendering if configured."""
|
|
22
|
-
return get_str_attr(
|
|
23
|
-
ctx,
|
|
24
|
-
conversation_history_file_attr,
|
|
25
|
-
"",
|
|
26
|
-
auto_render=render_history_file,
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
async def read_conversation_history(
|
|
31
|
-
ctx: AnyContext,
|
|
32
|
-
conversation_history_reader: (
|
|
33
|
-
Callable[[AnySharedContext], ConversationHistory | dict | list | None] | None
|
|
34
|
-
),
|
|
35
|
-
conversation_history_file_attr: StrAttr | None,
|
|
36
|
-
render_history_file: bool,
|
|
37
|
-
conversation_history_attr: (
|
|
38
|
-
ConversationHistory
|
|
39
|
-
| Callable[[AnySharedContext], ConversationHistory | dict | list]
|
|
40
|
-
| dict
|
|
41
|
-
| list
|
|
42
|
-
),
|
|
43
|
-
) -> ConversationHistory:
|
|
44
|
-
"""Reads conversation history from reader, file, or attribute, with validation."""
|
|
45
|
-
history_file = get_history_file(
|
|
46
|
-
ctx, conversation_history_file_attr, render_history_file
|
|
47
|
-
)
|
|
48
|
-
# Use the class method defined above
|
|
49
|
-
history_data = await ConversationHistory.read_from_source(
|
|
50
|
-
ctx=ctx,
|
|
51
|
-
reader=conversation_history_reader,
|
|
52
|
-
file_path=history_file,
|
|
53
|
-
)
|
|
54
|
-
if history_data:
|
|
55
|
-
return history_data
|
|
56
|
-
# Priority 3: Callable or direct conversation_history attribute
|
|
57
|
-
raw_data_attr: Any = None
|
|
58
|
-
if callable(conversation_history_attr):
|
|
59
|
-
try:
|
|
60
|
-
raw_data_attr = await run_async(conversation_history_attr(ctx))
|
|
61
|
-
except Exception as e:
|
|
62
|
-
ctx.log_warning(
|
|
63
|
-
f"Error executing callable conversation_history attribute: {e}. "
|
|
64
|
-
"Ignoring."
|
|
65
|
-
)
|
|
66
|
-
if raw_data_attr is None:
|
|
67
|
-
raw_data_attr = conversation_history_attr
|
|
68
|
-
if raw_data_attr:
|
|
69
|
-
# Use the class method defined above
|
|
70
|
-
history_data = ConversationHistory.parse_and_validate(
|
|
71
|
-
ctx, raw_data_attr, "attribute"
|
|
72
|
-
)
|
|
73
|
-
if history_data:
|
|
74
|
-
return history_data
|
|
75
|
-
# Fallback: Return default value
|
|
76
|
-
return ConversationHistory()
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
async def write_conversation_history(
|
|
80
|
-
ctx: AnyContext,
|
|
81
|
-
history_data: ConversationHistory,
|
|
82
|
-
conversation_history_writer: (
|
|
83
|
-
Callable[[AnySharedContext, ConversationHistory], None] | None
|
|
84
|
-
),
|
|
85
|
-
conversation_history_file_attr: StrAttr | None,
|
|
86
|
-
render_history_file: bool,
|
|
87
|
-
):
|
|
88
|
-
"""Writes conversation history using the writer or to a file."""
|
|
89
|
-
if conversation_history_writer is not None:
|
|
90
|
-
await run_async(conversation_history_writer(ctx, history_data))
|
|
91
|
-
history_file = get_history_file(
|
|
92
|
-
ctx, conversation_history_file_attr, render_history_file
|
|
93
|
-
)
|
|
94
|
-
if history_file != "":
|
|
95
|
-
write_file(history_file, json.dumps(history_data.to_dict(), indent=2))
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def replace_system_prompt_in_history(
|
|
99
|
-
history_list: ListOfDict, replacement: str = "<main LLM system prompt>"
|
|
100
|
-
) -> ListOfDict:
|
|
101
|
-
"""
|
|
102
|
-
Returns a new history list where any part with part_kind 'system-prompt'
|
|
103
|
-
has its 'content' replaced with the given replacement string.
|
|
104
|
-
Args:
|
|
105
|
-
history: List of history items (each item is a dict with a 'parts' list).
|
|
106
|
-
replacement: The string to use in place of system-prompt content.
|
|
107
|
-
|
|
108
|
-
Returns:
|
|
109
|
-
A deep-copied list of history items with system-prompt content replaced.
|
|
110
|
-
"""
|
|
111
|
-
new_history = deepcopy(history_list)
|
|
112
|
-
for item in new_history:
|
|
113
|
-
parts = item.get("parts", [])
|
|
114
|
-
for part in parts:
|
|
115
|
-
if part.get("part_kind") == "system-prompt":
|
|
116
|
-
part["content"] = replacement
|
|
117
|
-
return new_history
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def count_part_in_history_list(history_list: ListOfDict) -> int:
|
|
121
|
-
"""Calculates the total number of 'parts' in a history list."""
|
|
122
|
-
history_part_len = 0
|
|
123
|
-
for history in history_list:
|
|
124
|
-
if "parts" in history:
|
|
125
|
-
history_part_len += len(history["parts"])
|
|
126
|
-
else:
|
|
127
|
-
history_part_len += 1
|
|
128
|
-
return history_part_len
|