zrb 1.0.0b3__py3-none-any.whl → 1.0.0b4__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.
- zrb/builtin/llm/llm_chat.py +83 -5
- zrb/builtin/llm/previous-session.js +13 -0
- zrb/builtin/llm/tool/api.py +29 -0
- zrb/builtin/todo.py +1 -0
- zrb/config.py +17 -11
- zrb/input/any_input.py +5 -0
- zrb/input/base_input.py +6 -0
- zrb/input/bool_input.py +2 -0
- zrb/input/float_input.py +2 -0
- zrb/input/int_input.py +2 -0
- zrb/input/option_input.py +2 -0
- zrb/input/password_input.py +2 -0
- zrb/input/text_input.py +2 -0
- zrb/runner/common_util.py +1 -1
- zrb/runner/web_route/static/resources/session/current-session.js +0 -1
- zrb/runner/web_route/static/resources/session/event.js +4 -1
- zrb/task/llm_task.py +35 -16
- {zrb-1.0.0b3.dist-info → zrb-1.0.0b4.dist-info}/METADATA +1 -1
- {zrb-1.0.0b3.dist-info → zrb-1.0.0b4.dist-info}/RECORD +21 -19
- {zrb-1.0.0b3.dist-info → zrb-1.0.0b4.dist-info}/WHEEL +0 -0
- {zrb-1.0.0b3.dist-info → zrb-1.0.0b4.dist-info}/entry_points.txt +0 -0
zrb/builtin/llm/llm_chat.py
CHANGED
@@ -1,17 +1,76 @@
|
|
1
|
+
import json
|
2
|
+
import os
|
3
|
+
from typing import Any
|
4
|
+
|
1
5
|
from zrb.builtin.group import llm_group
|
6
|
+
from zrb.builtin.llm.tool.api import get_current_location, get_current_weather
|
2
7
|
from zrb.builtin.llm.tool.cli import run_shell_command
|
3
|
-
from zrb.builtin.llm.tool.rag import create_rag_from_directory
|
4
8
|
from zrb.builtin.llm.tool.web import open_web_route, query_internet
|
5
9
|
from zrb.config import (
|
10
|
+
LLM_ALLOW_ACCESS_INTERNET,
|
6
11
|
LLM_ALLOW_ACCESS_SHELL,
|
7
|
-
|
8
|
-
LLM_HISTORY_FILE,
|
12
|
+
LLM_HISTORY_DIR,
|
9
13
|
LLM_MODEL,
|
10
14
|
LLM_SYSTEM_PROMPT,
|
11
15
|
)
|
16
|
+
from zrb.context.any_shared_context import AnySharedContext
|
17
|
+
from zrb.input.bool_input import BoolInput
|
12
18
|
from zrb.input.str_input import StrInput
|
13
19
|
from zrb.input.text_input import TextInput
|
14
20
|
from zrb.task.llm_task import LLMTask
|
21
|
+
from zrb.util.file import read_file, write_file
|
22
|
+
from zrb.util.string.conversion import to_pascal_case
|
23
|
+
|
24
|
+
|
25
|
+
class PreviousSessionInput(StrInput):
|
26
|
+
|
27
|
+
def to_html(self, ctx: AnySharedContext) -> str:
|
28
|
+
name = self.name
|
29
|
+
description = self.description
|
30
|
+
default = self.get_default_str(ctx)
|
31
|
+
script = read_file(
|
32
|
+
file_path=os.path.join(os.path.dirname(__file__), "previous-session.js"),
|
33
|
+
replace_map={
|
34
|
+
"CURRENT_INPUT_NAME": name,
|
35
|
+
"CurrentPascalInputName": to_pascal_case(name),
|
36
|
+
},
|
37
|
+
)
|
38
|
+
return "\n".join(
|
39
|
+
[
|
40
|
+
f'<input name="{name}" placeholder="{description}" value="{default}" />',
|
41
|
+
f"<script>{script}</script>",
|
42
|
+
]
|
43
|
+
)
|
44
|
+
|
45
|
+
|
46
|
+
def _read_chat_conversation(ctx: AnySharedContext) -> list[dict[str, Any]]:
|
47
|
+
if ctx.input.start_new:
|
48
|
+
return []
|
49
|
+
previous_session_name = ctx.input.previous_session
|
50
|
+
if previous_session_name == "" or previous_session_name is None:
|
51
|
+
last_session_file_path = os.path.join(LLM_HISTORY_DIR, "last-session")
|
52
|
+
if os.path.isfile(last_session_file_path):
|
53
|
+
previous_session_name = read_file(last_session_file_path).strip()
|
54
|
+
conversation_file_path = os.path.join(
|
55
|
+
LLM_HISTORY_DIR, f"{previous_session_name}.json"
|
56
|
+
)
|
57
|
+
if not os.path.isfile(conversation_file_path):
|
58
|
+
return []
|
59
|
+
return json.loads(read_file(conversation_file_path))
|
60
|
+
|
61
|
+
|
62
|
+
def _write_chat_conversation(
|
63
|
+
ctx: AnySharedContext, conversations: list[dict[str, Any]]
|
64
|
+
):
|
65
|
+
os.makedirs(LLM_HISTORY_DIR, exist_ok=True)
|
66
|
+
current_session_name = ctx.session.name
|
67
|
+
conversation_file_path = os.path.join(
|
68
|
+
LLM_HISTORY_DIR, f"{current_session_name}.json"
|
69
|
+
)
|
70
|
+
write_file(conversation_file_path, json.dumps(conversations, indent=2))
|
71
|
+
last_session_file_path = os.path.join(LLM_HISTORY_DIR, "last-session")
|
72
|
+
write_file(last_session_file_path, current_session_name)
|
73
|
+
|
15
74
|
|
16
75
|
llm_chat: LLMTask = llm_group.add_task(
|
17
76
|
LLMTask(
|
@@ -22,16 +81,33 @@ llm_chat: LLMTask = llm_group.add_task(
|
|
22
81
|
description="LLM Model",
|
23
82
|
prompt="LLM Model",
|
24
83
|
default_str=LLM_MODEL,
|
84
|
+
allow_positional_parsing=False,
|
25
85
|
),
|
26
86
|
TextInput(
|
27
87
|
"system-prompt",
|
28
88
|
description="System prompt",
|
29
89
|
prompt="System prompt",
|
30
90
|
default_str=LLM_SYSTEM_PROMPT,
|
91
|
+
allow_positional_parsing=False,
|
92
|
+
),
|
93
|
+
BoolInput(
|
94
|
+
"start-new",
|
95
|
+
description="Start new conversation session",
|
96
|
+
prompt="Forget everything and start new conversation session",
|
97
|
+
default_str="false",
|
98
|
+
allow_positional_parsing=False,
|
31
99
|
),
|
32
100
|
TextInput("message", description="User message", prompt="Your message"),
|
101
|
+
PreviousSessionInput(
|
102
|
+
"previous-session",
|
103
|
+
description="Previous conversation session",
|
104
|
+
prompt="Previous conversation session (can be empty)",
|
105
|
+
allow_positional_parsing=False,
|
106
|
+
allow_empty=True,
|
107
|
+
),
|
33
108
|
],
|
34
|
-
|
109
|
+
conversation_history_reader=_read_chat_conversation,
|
110
|
+
conversation_history_writer=_write_chat_conversation,
|
35
111
|
description="Chat with LLM",
|
36
112
|
model="{ctx.input.model}",
|
37
113
|
system_prompt="{ctx.input['system-prompt']}",
|
@@ -44,6 +120,8 @@ llm_chat: LLMTask = llm_group.add_task(
|
|
44
120
|
if LLM_ALLOW_ACCESS_SHELL:
|
45
121
|
llm_chat.add_tool(run_shell_command)
|
46
122
|
|
47
|
-
if
|
123
|
+
if LLM_ALLOW_ACCESS_INTERNET:
|
48
124
|
llm_chat.add_tool(open_web_route)
|
49
125
|
llm_chat.add_tool(query_internet)
|
126
|
+
llm_chat.add_tool(get_current_location)
|
127
|
+
llm_chat.add_tool(get_current_weather)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
let hasUpdateCurrentPascalInputName = false;
|
2
|
+
document.getElementById("submit-task-form").addEventListener("change", async function(event) {
|
3
|
+
const currentInput = event.target;
|
4
|
+
if (hasUpdateCurrentPascalInputName || currentInput.name === "CURRENT_INPUT_NAME") {
|
5
|
+
return
|
6
|
+
}
|
7
|
+
const previousSessionInput = submitTaskForm.querySelector('[name="CURRENT_INPUT_NAME"]');
|
8
|
+
if (previousSessionInput) {
|
9
|
+
const currentSessionName = cfg.SESSION_NAME
|
10
|
+
previousSessionInput.value = currentSessionName;
|
11
|
+
}
|
12
|
+
hasUpdateCurrentPascalInputName = true;
|
13
|
+
});
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import json
|
2
|
+
from typing import Annotated, Literal
|
3
|
+
|
4
|
+
import requests
|
5
|
+
|
6
|
+
|
7
|
+
def get_current_location() -> (
|
8
|
+
Annotated[str, "JSON string representing latitude and longitude"]
|
9
|
+
): # noqa
|
10
|
+
"""Get the user's current location."""
|
11
|
+
return json.dumps(requests.get("http://ip-api.com/json?fields=lat,lon").json())
|
12
|
+
|
13
|
+
|
14
|
+
def get_current_weather(
|
15
|
+
latitude: float,
|
16
|
+
longitude: float,
|
17
|
+
temperature_unit: Literal["celsius", "fahrenheit"],
|
18
|
+
) -> str:
|
19
|
+
"""Get the current weather in a given location."""
|
20
|
+
resp = requests.get(
|
21
|
+
"https://api.open-meteo.com/v1/forecast",
|
22
|
+
params={
|
23
|
+
"latitude": latitude,
|
24
|
+
"longitude": longitude,
|
25
|
+
"temperature_unit": temperature_unit,
|
26
|
+
"current_weather": True,
|
27
|
+
},
|
28
|
+
)
|
29
|
+
return json.dumps(resp.json())
|
zrb/builtin/todo.py
CHANGED
@@ -294,6 +294,7 @@ def _get_default_stop_work_time_str() -> str:
|
|
294
294
|
description="Todo.txt content",
|
295
295
|
prompt="Todo.txt content (will override existing)",
|
296
296
|
default_str=lambda _: _get_todo_txt_content(),
|
297
|
+
allow_positional_parsing=False,
|
297
298
|
),
|
298
299
|
],
|
299
300
|
description="📝 Edit todo",
|
zrb/config.py
CHANGED
@@ -79,24 +79,30 @@ WEB_AUTH_REFRESH_TOKEN_EXPIRE_MINUTES = int(
|
|
79
79
|
LLM_MODEL = os.getenv("ZRB_LLM_MODEL", "ollama_chat/llama3.1")
|
80
80
|
|
81
81
|
_DEFAULT_PROMPT = """
|
82
|
-
You are a
|
82
|
+
You are a helpful assistant and you have access to several tools.
|
83
|
+
Your goal is to provide a final answer by executing a series of planning, actions, reasoning, and evaluations.
|
83
84
|
|
84
|
-
|
85
|
-
1. Prioritize correctness and clarity.
|
86
|
-
2. Avoid guessing—clearly state if more information is needed.
|
87
|
-
3. Distinguish facts from opinions.
|
88
|
-
4. Use phrases like "to the best of my knowledge" when appropriate.
|
85
|
+
Breakdown user request into several actionable tasks. For example, when user ask about current weather on current location, you should get the current location first.
|
89
86
|
|
90
|
-
|
91
|
-
|
87
|
+
DO NOT TRY TO SIMULATE TOOL OUTPUT.
|
88
|
+
|
89
|
+
ERROR HANDLING
|
90
|
+
1. If you receive an error, read the error message carefully and identify the specific issue.
|
91
|
+
2. Adjust your response accordingly and perform the review process again before resubmitting.
|
92
|
+
|
93
|
+
REMINDER:
|
94
|
+
- ALWAYS double-check your response format and function arguments before submitting.
|
95
|
+
- DON'T make up answers.
|
92
96
|
""".strip()
|
93
97
|
LLM_SYSTEM_PROMPT = os.getenv("ZRB_LLM_SYSTEM_PROMPT", _DEFAULT_PROMPT)
|
98
|
+
LLM_HISTORY_DIR = os.getenv(
|
99
|
+
"ZRB_LLM_HISTORY_DIR", os.path.expanduser(os.path.join("~", ".zrb-llm-history"))
|
100
|
+
)
|
94
101
|
LLM_HISTORY_FILE = os.getenv(
|
95
|
-
"ZRB_LLM_HISTORY_FILE",
|
96
|
-
os.path.expanduser(os.path.join("~", ".zrb-llm-history.json")),
|
102
|
+
"ZRB_LLM_HISTORY_FILE", os.path.join(LLM_HISTORY_DIR, "history.json")
|
97
103
|
)
|
98
104
|
LLM_ALLOW_ACCESS_SHELL = to_boolean(os.getenv("ZRB_LLM_ACCESS_FILE", "1"))
|
99
|
-
|
105
|
+
LLM_ALLOW_ACCESS_INTERNET = to_boolean(os.getenv("ZRB_LLM_ACCESS_INTERNET", "1"))
|
100
106
|
RAG_EMBEDDING_MODEL = os.getenv("ZRB_RAG_EMBEDDING_MODEL", "ollama/nomic-embed-text")
|
101
107
|
RAG_CHUNK_SIZE = int(os.getenv("ZRB_RAG_CHUNK_SIZE", "1024"))
|
102
108
|
RAG_OVERLAP = int(os.getenv("ZRB_RAG_OVERLAP", "128"))
|
zrb/input/any_input.py
CHANGED
zrb/input/base_input.py
CHANGED
@@ -16,6 +16,7 @@ class BaseInput(AnyInput):
|
|
16
16
|
default_str: StrAttr = "",
|
17
17
|
auto_render: bool = True,
|
18
18
|
allow_empty: bool = False,
|
19
|
+
allow_positional_parsing: bool = True,
|
19
20
|
):
|
20
21
|
self._name = name
|
21
22
|
self._description = description
|
@@ -23,6 +24,7 @@ class BaseInput(AnyInput):
|
|
23
24
|
self._default_str = default_str
|
24
25
|
self._auto_render = auto_render
|
25
26
|
self._allow_empty = allow_empty
|
27
|
+
self._allow_positional_parsing = allow_positional_parsing
|
26
28
|
|
27
29
|
def __repr__(self):
|
28
30
|
return f"<{self.__class__.__name__} name={self._name}>"
|
@@ -39,6 +41,10 @@ class BaseInput(AnyInput):
|
|
39
41
|
def prompt_message(self) -> str:
|
40
42
|
return self._prompt if self._prompt is not None else self.name
|
41
43
|
|
44
|
+
@property
|
45
|
+
def allow_positional_parsing(self) -> bool:
|
46
|
+
return self._allow_positional_parsing
|
47
|
+
|
42
48
|
def to_html(self, ctx: AnySharedContext) -> str:
|
43
49
|
name = self.name
|
44
50
|
description = self.description
|
zrb/input/bool_input.py
CHANGED
@@ -13,6 +13,7 @@ class BoolInput(BaseInput):
|
|
13
13
|
default_str: StrAttr = "False",
|
14
14
|
auto_render: bool = True,
|
15
15
|
allow_empty: bool = False,
|
16
|
+
allow_positional_parsing: bool = True,
|
16
17
|
):
|
17
18
|
super().__init__(
|
18
19
|
name=name,
|
@@ -21,6 +22,7 @@ class BoolInput(BaseInput):
|
|
21
22
|
default_str=default_str,
|
22
23
|
auto_render=auto_render,
|
23
24
|
allow_empty=allow_empty,
|
25
|
+
allow_positional_parsing=allow_positional_parsing,
|
24
26
|
)
|
25
27
|
|
26
28
|
def to_html(self, ctx: AnySharedContext) -> str:
|
zrb/input/float_input.py
CHANGED
@@ -12,6 +12,7 @@ class FloatInput(BaseInput):
|
|
12
12
|
default_str: StrAttr = "0.0",
|
13
13
|
auto_render: bool = True,
|
14
14
|
allow_empty: bool = False,
|
15
|
+
allow_positional_parsing: bool = True,
|
15
16
|
):
|
16
17
|
super().__init__(
|
17
18
|
name=name,
|
@@ -20,6 +21,7 @@ class FloatInput(BaseInput):
|
|
20
21
|
default_str=default_str,
|
21
22
|
auto_render=auto_render,
|
22
23
|
allow_empty=allow_empty,
|
24
|
+
allow_positional_parsing=allow_positional_parsing,
|
23
25
|
)
|
24
26
|
|
25
27
|
def to_html(self, ctx: AnySharedContext) -> str:
|
zrb/input/int_input.py
CHANGED
@@ -12,6 +12,7 @@ class IntInput(BaseInput):
|
|
12
12
|
default_str: StrAttr = "0",
|
13
13
|
auto_render: bool = True,
|
14
14
|
allow_empty: bool = False,
|
15
|
+
allow_positional_parsing: bool = True,
|
15
16
|
):
|
16
17
|
super().__init__(
|
17
18
|
name=name,
|
@@ -20,6 +21,7 @@ class IntInput(BaseInput):
|
|
20
21
|
default_str=default_str,
|
21
22
|
auto_render=auto_render,
|
22
23
|
allow_empty=allow_empty,
|
24
|
+
allow_positional_parsing=allow_positional_parsing,
|
23
25
|
)
|
24
26
|
|
25
27
|
def to_html(self, ctx: AnySharedContext) -> str:
|
zrb/input/option_input.py
CHANGED
@@ -14,6 +14,7 @@ class OptionInput(BaseInput):
|
|
14
14
|
default_str: StrAttr = "",
|
15
15
|
auto_render: bool = True,
|
16
16
|
allow_empty: bool = False,
|
17
|
+
allow_positional_parsing: bool = True,
|
17
18
|
):
|
18
19
|
super().__init__(
|
19
20
|
name=name,
|
@@ -22,6 +23,7 @@ class OptionInput(BaseInput):
|
|
22
23
|
default_str=default_str,
|
23
24
|
auto_render=auto_render,
|
24
25
|
allow_empty=allow_empty,
|
26
|
+
allow_positional_parsing=allow_positional_parsing,
|
25
27
|
)
|
26
28
|
self._options = options
|
27
29
|
|
zrb/input/password_input.py
CHANGED
@@ -14,6 +14,7 @@ class PasswordInput(BaseInput):
|
|
14
14
|
default_str: str | Callable[[AnySharedContext], str] = "",
|
15
15
|
auto_render: bool = True,
|
16
16
|
allow_empty: bool = False,
|
17
|
+
allow_positional_parsing: bool = True,
|
17
18
|
):
|
18
19
|
super().__init__(
|
19
20
|
name=name,
|
@@ -22,6 +23,7 @@ class PasswordInput(BaseInput):
|
|
22
23
|
default_str=default_str,
|
23
24
|
auto_render=auto_render,
|
24
25
|
allow_empty=allow_empty,
|
26
|
+
allow_positional_parsing=allow_positional_parsing,
|
25
27
|
)
|
26
28
|
self._is_secret = True
|
27
29
|
|
zrb/input/text_input.py
CHANGED
@@ -18,6 +18,7 @@ class TextInput(BaseInput):
|
|
18
18
|
default_str: str | Callable[[AnySharedContext], str] = "",
|
19
19
|
auto_render: bool = True,
|
20
20
|
allow_empty: bool = False,
|
21
|
+
allow_positional_parsing: bool = True,
|
21
22
|
editor: str = DEFAULT_EDITOR,
|
22
23
|
extension: str = ".txt",
|
23
24
|
comment_start: str | None = None,
|
@@ -30,6 +31,7 @@ class TextInput(BaseInput):
|
|
30
31
|
default_str=default_str,
|
31
32
|
auto_render=auto_render,
|
32
33
|
allow_empty=allow_empty,
|
34
|
+
allow_positional_parsing=allow_positional_parsing,
|
33
35
|
)
|
34
36
|
self._editor = editor
|
35
37
|
self._extension = extension
|
zrb/runner/common_util.py
CHANGED
@@ -15,7 +15,7 @@ def get_run_kwargs(
|
|
15
15
|
if task_input.name in str_kwargs:
|
16
16
|
# Update shared context for next input default value
|
17
17
|
task_input.update_shared_context(shared_ctx, str_kwargs[task_input.name])
|
18
|
-
elif arg_index < len(args):
|
18
|
+
elif arg_index < len(args) and task_input.allow_positional_parsing:
|
19
19
|
run_kwargs[task_input.name] = args[arg_index]
|
20
20
|
# Update shared context for next input default value
|
21
21
|
task_input.update_shared_context(shared_ctx, run_kwargs[task_input.name])
|
@@ -22,7 +22,7 @@ window.addEventListener("load", async function () {
|
|
22
22
|
const submitTaskForm = document.getElementById("submit-task-form");
|
23
23
|
submitTaskForm.addEventListener("change", async function(event) {
|
24
24
|
const currentInput = event.target;
|
25
|
-
const inputs = Array.from(submitTaskForm.querySelectorAll("input[name], textarea[name]"));
|
25
|
+
const inputs = Array.from(submitTaskForm.querySelectorAll("input[name], textarea[name], select[name]"));
|
26
26
|
const inputMap = {};
|
27
27
|
const fixedInputNames = [];
|
28
28
|
for (const input of inputs) {
|
@@ -56,6 +56,9 @@ submitTaskForm.addEventListener("change", async function(event) {
|
|
56
56
|
if (input === currentInput) {
|
57
57
|
return;
|
58
58
|
}
|
59
|
+
if (value === "") {
|
60
|
+
return;
|
61
|
+
}
|
59
62
|
input.value = value;
|
60
63
|
});
|
61
64
|
} else {
|
zrb/task/llm_task.py
CHANGED
@@ -28,7 +28,7 @@ class AdditionalTool(BaseModel):
|
|
28
28
|
|
29
29
|
|
30
30
|
def scratchpad(thought: str) -> str:
|
31
|
-
"""
|
31
|
+
"""Write your thought, analysis, reasoning, and evaluation here."""
|
32
32
|
return thought
|
33
33
|
|
34
34
|
|
@@ -53,8 +53,16 @@ class LLMTask(BaseTask):
|
|
53
53
|
render_system_prompt: bool = True,
|
54
54
|
message: StrAttr | None = None,
|
55
55
|
tools: list[Callable] | Callable[[AnySharedContext], list[Callable]] = [],
|
56
|
-
|
57
|
-
|
56
|
+
conversation_history: (
|
57
|
+
ListOfDict | Callable[[AnySharedContext], ListOfDict]
|
58
|
+
) = [],
|
59
|
+
conversation_history_reader: (
|
60
|
+
Callable[[AnySharedContext], ListOfDict] | None
|
61
|
+
) = None,
|
62
|
+
conversation_history_writer: (
|
63
|
+
Callable[[AnySharedContext, ListOfDict], None] | None
|
64
|
+
) = None,
|
65
|
+
conversation_history_file: StrAttr | None = None,
|
58
66
|
render_history_file: bool = True,
|
59
67
|
model_kwargs: (
|
60
68
|
dict[str, Any] | Callable[[AnySharedContext], dict[str, Any]]
|
@@ -100,8 +108,10 @@ class LLMTask(BaseTask):
|
|
100
108
|
self._render_system_prompt = render_system_prompt
|
101
109
|
self._message = message
|
102
110
|
self._tools = tools
|
103
|
-
self.
|
104
|
-
self.
|
111
|
+
self._conversation_history = conversation_history
|
112
|
+
self._conversation_history_reader = conversation_history_reader
|
113
|
+
self._conversation_history_writer = conversation_history_writer
|
114
|
+
self._conversation_history_file = conversation_history_file
|
105
115
|
self._render_history_file = render_history_file
|
106
116
|
|
107
117
|
def add_tool(self, tool: Callable):
|
@@ -128,10 +138,9 @@ class LLMTask(BaseTask):
|
|
128
138
|
ctx.log_debug("MODEL KWARGS", model_kwargs)
|
129
139
|
system_prompt = self._get_system_prompt(ctx)
|
130
140
|
ctx.log_debug("SYSTEM PROMPT", system_prompt)
|
131
|
-
history = self.
|
141
|
+
history = await self._read_conversation_history(ctx)
|
132
142
|
ctx.log_debug("HISTORY PROMPT", history)
|
133
143
|
conversations = history + [user_message]
|
134
|
-
history_file = self._get_history_file(ctx)
|
135
144
|
while True:
|
136
145
|
llm_response = await self._get_llm_response(
|
137
146
|
model, system_prompt, conversations, model_kwargs
|
@@ -143,7 +152,7 @@ class LLMTask(BaseTask):
|
|
143
152
|
if is_function_call_supported:
|
144
153
|
if not llm_response.tool_calls:
|
145
154
|
# No tool call, end conversation
|
146
|
-
self.
|
155
|
+
await self._write_conversation_history(ctx, conversations)
|
147
156
|
return llm_response.content
|
148
157
|
await self._handle_tool_calls(
|
149
158
|
ctx, available_tools, conversations, llm_response
|
@@ -161,7 +170,7 @@ class LLMTask(BaseTask):
|
|
161
170
|
ctx.print(stylize_faint(f"{tool_execution_message}"))
|
162
171
|
conversations.append(tool_execution_message)
|
163
172
|
if function_name == "end_conversation":
|
164
|
-
self.
|
173
|
+
await self._write_conversation_history(ctx, conversations)
|
165
174
|
return function_kwargs.get("final_answer", "")
|
166
175
|
except Exception as e:
|
167
176
|
ctx.log_error(e)
|
@@ -185,7 +194,12 @@ class LLMTask(BaseTask):
|
|
185
194
|
ctx.print(stylize_faint(f"{tool_execution_message}"))
|
186
195
|
conversations.append(tool_execution_message)
|
187
196
|
|
188
|
-
def
|
197
|
+
async def _write_conversation_history(
|
198
|
+
self, ctx: AnyContext, conversations: list[Any]
|
199
|
+
):
|
200
|
+
if self._conversation_history_writer is not None:
|
201
|
+
await run_async(self._conversation_history_writer(ctx, conversations))
|
202
|
+
history_file = self._get_history_file(ctx)
|
189
203
|
if history_file != "":
|
190
204
|
write_file(history_file, json.dumps(conversations, indent=2))
|
191
205
|
|
@@ -294,21 +308,26 @@ class LLMTask(BaseTask):
|
|
294
308
|
tools[tool.__name__] = tool
|
295
309
|
return tools
|
296
310
|
|
297
|
-
def
|
298
|
-
if
|
299
|
-
return self.
|
311
|
+
async def _read_conversation_history(self, ctx: AnyContext) -> ListOfDict:
|
312
|
+
if self._conversation_history_reader is not None:
|
313
|
+
return await run_async(self._conversation_history_reader(ctx))
|
314
|
+
if callable(self._conversation_history):
|
315
|
+
return self._conversation_history(ctx)
|
300
316
|
history_file = self._get_history_file(ctx)
|
301
317
|
if (
|
302
|
-
len(self.
|
318
|
+
len(self._conversation_history) == 0
|
303
319
|
and history_file != ""
|
304
320
|
and os.path.isfile(history_file)
|
305
321
|
):
|
306
322
|
return json.loads(read_file(history_file))
|
307
|
-
return self.
|
323
|
+
return self._conversation_history
|
308
324
|
|
309
325
|
def _get_history_file(self, ctx: AnyContext) -> str:
|
310
326
|
return get_str_attr(
|
311
|
-
ctx,
|
327
|
+
ctx,
|
328
|
+
self._conversation_history_file,
|
329
|
+
"",
|
330
|
+
auto_render=self._render_history_file,
|
312
331
|
)
|
313
332
|
|
314
333
|
|
@@ -7,7 +7,9 @@ zrb/builtin/base64.py,sha256=1YnSwASp7OEAvQcsnHZGpJEvYoI1Z2zTIJ1bCDHfcPQ,921
|
|
7
7
|
zrb/builtin/git.py,sha256=xHzg0srhp1uOSXWvwA--Fo8idkt0G9010iJ8uIndzg4,5463
|
8
8
|
zrb/builtin/git_subtree.py,sha256=GwI8befmvXEoX1xyZ4jkeG8nsyCkuRG1lzPiGss3yqw,3493
|
9
9
|
zrb/builtin/group.py,sha256=-phJfVpTX3_gUwS1u8-RbZUHe-X41kxDBSmrVh4rq8E,1682
|
10
|
-
zrb/builtin/llm/llm_chat.py,sha256
|
10
|
+
zrb/builtin/llm/llm_chat.py,sha256=zrUzVjHBTOJS81--npePIJQo7zzmeERUVRMon91yI3c,4488
|
11
|
+
zrb/builtin/llm/previous-session.js,sha256=lZcQIdxr_5Qygm9U2tkMlOg_-gz7G-r6YEdQqz0_RnE,578
|
12
|
+
zrb/builtin/llm/tool/api.py,sha256=yQ3XV8O7Fx7hHssLSOcmiHDnevPhz9ktWi44HK7zTls,801
|
11
13
|
zrb/builtin/llm/tool/cli.py,sha256=to_IjkfrMGs6eLfG0cpVN9oyADWYsJQCtyluUhUdBww,253
|
12
14
|
zrb/builtin/llm/tool/rag.py,sha256=jJRLERW6824JeEzEQ_OqLMaaa3mjuNqsRcRWoL1wVx0,5192
|
13
15
|
zrb/builtin/llm/tool/web.py,sha256=N2HYuXbKPUpjVAq_UnQMbUrTIE8u0Ut3TeQadZ7_NJc,2217
|
@@ -162,14 +164,14 @@ zrb/builtin/shell/autocomplete/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
|
|
162
164
|
zrb/builtin/shell/autocomplete/bash.py,sha256=-7YDVV7txgJH9mAYSYN0jmvUEeDIzWFvVNY-cY0myF8,1181
|
163
165
|
zrb/builtin/shell/autocomplete/subcmd.py,sha256=WZI6cGWJcn80zSyxOHG7sCMO3Ucix3mZf4xm_xyB_Y0,606
|
164
166
|
zrb/builtin/shell/autocomplete/zsh.py,sha256=9hlq0Wt3fhRz326mAQTypEd4_4lZdrbBx_3A-Ti3mvw,1022
|
165
|
-
zrb/builtin/todo.py,sha256=
|
167
|
+
zrb/builtin/todo.py,sha256=8swb5i9KWqaLfKKcKSQhu5K1QtW3RAYR1vFqsBjw-GY,10840
|
166
168
|
zrb/callback/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
167
169
|
zrb/callback/any_callback.py,sha256=Yhdv5UWHAZSVzj5K2JdxcVQx8x8VX8aZJEivj3NTfZc,247
|
168
170
|
zrb/callback/callback.py,sha256=hKefB_Jd1XGjPSLQdMKDsGLHPzEGO2dqrIArLl_EmD0,848
|
169
171
|
zrb/cmd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
170
172
|
zrb/cmd/cmd_result.py,sha256=L8bQJzWCpcYexIxHBNsXj2pT3BtLmWex0iJSMkvimOA,597
|
171
173
|
zrb/cmd/cmd_val.py,sha256=7Doowyg6BK3ISSGBLt-PmlhzaEkBjWWm51cED6fAUOQ,1014
|
172
|
-
zrb/config.py,sha256=
|
174
|
+
zrb/config.py,sha256=tFPjLqgcb6cH33trooDgJRsoJBSneB03ccnzx90iH9M,4664
|
173
175
|
zrb/content_transformer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
174
176
|
zrb/content_transformer/any_content_transformer.py,sha256=v8ZUbcix1GGeDQwB6OKX_1TjpY__ksxWVeqibwa_iZA,850
|
175
177
|
zrb/content_transformer/content_transformer.py,sha256=YU6Xr3G_IaCWKQGsf9z9YlCclbiwcJ7ytQv3wKpPIiI,2125
|
@@ -189,18 +191,18 @@ zrb/group/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
189
191
|
zrb/group/any_group.py,sha256=1rNcsi5eu_86JAx_6Jy46SK4BTeppcb89MORynJd-4o,1115
|
190
192
|
zrb/group/group.py,sha256=JFmWVEQ9PVy2WCf5pUG74iwL2xcGxXaAjT-NArAeloM,1861
|
191
193
|
zrb/input/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
192
|
-
zrb/input/any_input.py,sha256=
|
193
|
-
zrb/input/base_input.py,sha256=
|
194
|
-
zrb/input/bool_input.py,sha256=
|
195
|
-
zrb/input/float_input.py,sha256=
|
196
|
-
zrb/input/int_input.py,sha256=
|
197
|
-
zrb/input/option_input.py,sha256=
|
198
|
-
zrb/input/password_input.py,sha256=
|
194
|
+
zrb/input/any_input.py,sha256=tvls3uJBVPLW5Oawxof9qWCX-lH1h_RErxjYNu1bwtY,899
|
195
|
+
zrb/input/base_input.py,sha256=uHOZeU4OyO05e-kMXDo5MLC76ZWJXzhdhB6akaBzhtU,3383
|
196
|
+
zrb/input/bool_input.py,sha256=mqD1c7RT683Aui2IsdJUoNiSo7iU3iYrm53e2SjaOrQ,1493
|
197
|
+
zrb/input/float_input.py,sha256=8HhVWZsyqw1WaN3CysIgvGXkHfVsuLChUEggHODxOTk,1125
|
198
|
+
zrb/input/int_input.py,sha256=e5F049nwe_Iaiymuh41dZtBOY-DG1AhVP-8gF0IO0n4,1115
|
199
|
+
zrb/input/option_input.py,sha256=8K0fn5joYeiAA8GevckVrGghbrIcD9GPShDfhAU67cw,2049
|
200
|
+
zrb/input/password_input.py,sha256=6TW3J7K3ilcstv681PIXL_Mgd6pkNDTCMH8exlqDOiM,1421
|
199
201
|
zrb/input/str_input.py,sha256=NevZHX9rf1g8eMatPyy-kUX3DglrVAQpzvVpKAzf7bA,81
|
200
|
-
zrb/input/text_input.py,sha256=
|
202
|
+
zrb/input/text_input.py,sha256=cVmuNBTFl7oulwG6VVWI-QTECLSdP_0xwIaCZpkkaM8,3143
|
201
203
|
zrb/runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
202
204
|
zrb/runner/cli.py,sha256=G_ILZCFzpV-kRE3dm1kq6BorB51TLJ34Qmhgy5SIMlU,6734
|
203
|
-
zrb/runner/common_util.py,sha256=
|
205
|
+
zrb/runner/common_util.py,sha256=mjEBSmfdY2Sun2U5-8y8gGwF82OiRM8sgiYDOdW9NA4,1338
|
204
206
|
zrb/runner/web_app.py,sha256=Ji2AWeFpJu5guXmur7mAAbjMToyjgmPDdfYu8047FFI,2616
|
205
207
|
zrb/runner/web_config/config.py,sha256=0wR58KreAmawGGfamm0GLZY344HaXs7qfDgHLavBDwo,3125
|
206
208
|
zrb/runner/web_config/config_factory.py,sha256=GNByKviNhQF5qG2ypmC_mV2xglzWHLVQC0x2SQJjrbA,894
|
@@ -232,8 +234,8 @@ zrb/runner/web_route/static/resources/login/event.js,sha256=1-NxaUwU-X7Tu2RAwVkz
|
|
232
234
|
zrb/runner/web_route/static/resources/logout/event.js,sha256=MfZxrTa2yL49Lbh7cCZDdqsIcf9e1q3W8-WjmZXV5pA,692
|
233
235
|
zrb/runner/web_route/static/resources/pico.min.css,sha256=_Esfkjs_U_igYn-tXBUaK3AEKb7d4l9DlmaOiw9bXfI,82214
|
234
236
|
zrb/runner/web_route/static/resources/session/common-util.js,sha256=t7_s5DXgMyZlT8L8LYZTkzOT6vWVeZvmCKjt-bflQY0,2117
|
235
|
-
zrb/runner/web_route/static/resources/session/current-session.js,sha256=
|
236
|
-
zrb/runner/web_route/static/resources/session/event.js,sha256=
|
237
|
+
zrb/runner/web_route/static/resources/session/current-session.js,sha256=Stewc8SOpv14ARJMlWJW4hegGMFCKwcnnNQZ2wKKW6I,6571
|
238
|
+
zrb/runner/web_route/static/resources/session/event.js,sha256=1WujNriQupSX-zE-uqXlrzgZn6jchDKzWTATvDuZjhA,4359
|
237
239
|
zrb/runner/web_route/static/resources/session/past-session.js,sha256=RwGJYKSp75K8NZ-iZP58XppWgdzkiKFaiC5wgcMLxDo,5470
|
238
240
|
zrb/runner/web_route/static/static_route.py,sha256=7x069VfACZLkLykY0vLL5t13jIQPgkeEJtkpbfNQfLg,1540
|
239
241
|
zrb/runner/web_route/task_input_api_route.py,sha256=xkZ36vmHXMPj0ekp6ocUysO0QUgl1PLaSHt3YL_OfK8,1749
|
@@ -260,7 +262,7 @@ zrb/task/base_task.py,sha256=ImA0ReyB6neVUfY4nKLnL0h2EMGIJ9wvvNvIAN92-RE,21194
|
|
260
262
|
zrb/task/base_trigger.py,sha256=jC722rDvodaBLeNaFghkTyv1u0QXrK6BLZUUqcmBJ7Q,4581
|
261
263
|
zrb/task/cmd_task.py,sha256=JpClYoEmJTqKSxhuCErXd2kHLS3Hk2zXeYnl7entNeU,10378
|
262
264
|
zrb/task/http_check.py,sha256=Gf5rOB2Se2EdizuN9rp65HpGmfZkGc-clIAlHmPVehs,2565
|
263
|
-
zrb/task/llm_task.py,sha256=
|
265
|
+
zrb/task/llm_task.py,sha256=Hxu2kaAMHPquCE96bBt5MFh9A2EF_-bYeAMf0fOqSz8,13466
|
264
266
|
zrb/task/make_task.py,sha256=PD3b_aYazthS8LHeJsLAhwKDEgdurQZpymJDKeN60u0,2265
|
265
267
|
zrb/task/rsync_task.py,sha256=pVVslZ46qgcpU_EKhyTQEQie8kUOMuTsVQdbQG2L-yk,6318
|
266
268
|
zrb/task/scaffolder.py,sha256=rME18w1HJUHXgi9eTYXx_T2G4JdqDYzBoNOkdOOo5-o,6806
|
@@ -301,7 +303,7 @@ zrb/util/string/name.py,sha256=8picJfUBXNpdh64GNaHv3om23QHhUZux7DguFLrXHp8,1163
|
|
301
303
|
zrb/util/todo.py,sha256=1nDdwPc22oFoK_1ZTXyf3638Bg6sqE2yp_U4_-frHoc,16015
|
302
304
|
zrb/xcom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
303
305
|
zrb/xcom/xcom.py,sha256=o79rxR9wphnShrcIushA0Qt71d_p3ZTxjNf7x9hJB78,1571
|
304
|
-
zrb-1.0.
|
305
|
-
zrb-1.0.
|
306
|
-
zrb-1.0.
|
307
|
-
zrb-1.0.
|
306
|
+
zrb-1.0.0b4.dist-info/METADATA,sha256=G-QIlz6Gls_B72tCDApTqI-7B0minjgSYXZJDBAqp8Y,4224
|
307
|
+
zrb-1.0.0b4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
308
|
+
zrb-1.0.0b4.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
|
309
|
+
zrb-1.0.0b4.dist-info/RECORD,,
|
File without changes
|
File without changes
|