zrb 1.9.17__py3-none-any.whl → 1.10.1__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/__init__.py +2 -2
- zrb/builtin/llm/history.py +3 -5
- zrb/builtin/llm/tool/cli.py +17 -13
- zrb/builtin/llm/tool/file.py +2 -2
- zrb/builtin/llm/tool/sub_agent.py +3 -5
- zrb/config/config.py +8 -12
- zrb/config/llm_config.py +132 -107
- zrb/config/llm_rate_limitter.py +13 -2
- zrb/task/llm/conversation_history.py +128 -0
- zrb/task/llm/conversation_history_model.py +438 -0
- zrb/task/llm/history_summarization.py +76 -26
- zrb/task/llm/prompt.py +106 -14
- zrb/task/llm_task.py +53 -92
- zrb/util/llm/prompt.py +18 -0
- {zrb-1.9.17.dist-info → zrb-1.10.1.dist-info}/METADATA +1 -1
- {zrb-1.9.17.dist-info → zrb-1.10.1.dist-info}/RECORD +18 -18
- zrb/task/llm/context.py +0 -58
- zrb/task/llm/context_enrichment.py +0 -172
- zrb/task/llm/history.py +0 -233
- {zrb-1.9.17.dist-info → zrb-1.10.1.dist-info}/WHEEL +0 -0
- {zrb-1.9.17.dist-info → zrb-1.10.1.dist-info}/entry_points.txt +0 -0
zrb/__init__.py
CHANGED
@@ -47,7 +47,7 @@ _LAZY_LOAD = {
|
|
47
47
|
"BaseTrigger": "zrb.task.base_trigger",
|
48
48
|
"CmdTask": "zrb.task.cmd_task",
|
49
49
|
"HttpCheck": "zrb.task.http_check",
|
50
|
-
"
|
50
|
+
"ConversationHistory": "zrb.task.llm.conversation_history",
|
51
51
|
"LLMTask": "zrb.task.llm_task",
|
52
52
|
"make_task": "zrb.task.make_task",
|
53
53
|
"RsyncTask": "zrb.task.rsync_task",
|
@@ -107,7 +107,7 @@ if TYPE_CHECKING:
|
|
107
107
|
from zrb.task.base_trigger import BaseTrigger
|
108
108
|
from zrb.task.cmd_task import CmdTask
|
109
109
|
from zrb.task.http_check import HttpCheck
|
110
|
-
from zrb.task.llm.
|
110
|
+
from zrb.task.llm.conversation_history import ConversationHistory
|
111
111
|
from zrb.task.llm_task import LLMTask
|
112
112
|
from zrb.task.make_task import make_task
|
113
113
|
from zrb.task.rsync_task import RsyncTask
|
zrb/builtin/llm/history.py
CHANGED
@@ -4,14 +4,14 @@ from typing import Any
|
|
4
4
|
|
5
5
|
from zrb.config.config import CFG
|
6
6
|
from zrb.context.any_shared_context import AnySharedContext
|
7
|
-
from zrb.task.llm.
|
7
|
+
from zrb.task.llm.conversation_history_model import ConversationHistory
|
8
8
|
from zrb.util.file import read_file, write_file
|
9
9
|
|
10
10
|
|
11
11
|
def read_chat_conversation(ctx: AnySharedContext) -> dict[str, Any] | list | None:
|
12
12
|
"""Reads conversation history from the session file.
|
13
13
|
Returns the raw dictionary or list loaded from JSON, or None if not found/empty.
|
14
|
-
The LLMTask will handle parsing this into
|
14
|
+
The LLMTask will handle parsing this into ConversationHistory.
|
15
15
|
"""
|
16
16
|
if ctx.input.start_new:
|
17
17
|
return None # Indicate no history to load
|
@@ -51,9 +51,7 @@ def read_chat_conversation(ctx: AnySharedContext) -> dict[str, Any] | list | Non
|
|
51
51
|
return None
|
52
52
|
|
53
53
|
|
54
|
-
def write_chat_conversation(
|
55
|
-
ctx: AnySharedContext, history_data: ConversationHistoryData
|
56
|
-
):
|
54
|
+
def write_chat_conversation(ctx: AnySharedContext, history_data: ConversationHistory):
|
57
55
|
"""Writes the conversation history data (including context) to a session file."""
|
58
56
|
os.makedirs(CFG.LLM_HISTORY_DIR, exist_ok=True)
|
59
57
|
current_session_name = ctx.session.name
|
zrb/builtin/llm/tool/cli.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import json
|
1
2
|
import subprocess
|
2
3
|
|
3
4
|
|
@@ -13,17 +14,20 @@ def run_shell_command(command: str) -> str:
|
|
13
14
|
command (str): The exact shell command to execute.
|
14
15
|
|
15
16
|
Returns:
|
16
|
-
str:
|
17
|
-
|
18
|
-
|
17
|
+
str: A JSON string containing return code, standard output (stdout),
|
18
|
+
and standard error (stderr) from the command.
|
19
|
+
Example: {"return_code": 0, "stdout": "ok", "stderr": ""}
|
19
20
|
"""
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
21
|
+
result = subprocess.run(
|
22
|
+
command,
|
23
|
+
shell=True,
|
24
|
+
capture_output=True,
|
25
|
+
text=True,
|
26
|
+
)
|
27
|
+
return json.dumps(
|
28
|
+
{
|
29
|
+
"return_code": result.returncode,
|
30
|
+
"stdout": result.stdout,
|
31
|
+
"stderr": result.stderr,
|
32
|
+
}
|
33
|
+
)
|
zrb/builtin/llm/tool/file.py
CHANGED
@@ -218,7 +218,7 @@ def read_from_file(
|
|
218
218
|
|
219
219
|
Returns:
|
220
220
|
str: A JSON object containing the file path, the requested content with line numbers, the start and end lines, and the total number of lines in the file.
|
221
|
-
Example: '{"path": "src/main.py", "content": "1
|
221
|
+
Example: '{"path": "src/main.py", "content": "1| import os\n2| \n3| print(\"Hello, World!\")", "start_line": 1, "end_line": 3, "total_lines": 3}'
|
222
222
|
Raises:
|
223
223
|
FileNotFoundError: If the specified file does not exist.
|
224
224
|
"""
|
@@ -492,7 +492,7 @@ def read_many_files(paths: List[str]) -> str:
|
|
492
492
|
|
493
493
|
Returns:
|
494
494
|
str: A JSON object where keys are the file paths and values are their corresponding contents, prefixed with line numbers. If a file cannot be read, its value will be an error message.
|
495
|
-
Example: '{"results": {"src/api.py": "1
|
495
|
+
Example: '{"results": {"src/api.py": "1| import ...", "config.yaml": "1| key: value"}}'
|
496
496
|
"""
|
497
497
|
results = {}
|
498
498
|
for path in paths:
|
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, Any, Coroutine
|
|
6
6
|
from zrb.context.any_context import AnyContext
|
7
7
|
from zrb.task.llm.agent import create_agent_instance, run_agent_iteration
|
8
8
|
from zrb.task.llm.config import get_model, get_model_settings
|
9
|
-
from zrb.task.llm.prompt import
|
9
|
+
from zrb.task.llm.prompt import get_system_and_user_prompt
|
10
10
|
|
11
11
|
if TYPE_CHECKING:
|
12
12
|
from pydantic_ai import Tool
|
@@ -69,14 +69,12 @@ def create_sub_agent_tool(
|
|
69
69
|
)
|
70
70
|
|
71
71
|
if system_prompt is None:
|
72
|
-
resolved_system_prompt =
|
72
|
+
resolved_system_prompt, query = get_system_and_user_prompt(
|
73
73
|
ctx=ctx,
|
74
|
+
user_message=query,
|
74
75
|
persona_attr=None,
|
75
|
-
render_persona=False,
|
76
76
|
system_prompt_attr=None,
|
77
|
-
render_system_prompt=False,
|
78
77
|
special_instruction_prompt_attr=None,
|
79
|
-
render_special_instruction_prompt=False,
|
80
78
|
)
|
81
79
|
else:
|
82
80
|
resolved_system_prompt = system_prompt
|
zrb/config/config.py
CHANGED
@@ -336,10 +336,6 @@ class Config:
|
|
336
336
|
"""Number of seconds to sleep when throttling is required."""
|
337
337
|
return float(os.getenv("ZRB_LLM_THROTTLE_SLEEP", "1.0"))
|
338
338
|
|
339
|
-
@property
|
340
|
-
def LLM_CONTEXT_ENRICHMENT_PROMPT(self) -> str | None:
|
341
|
-
return os.getenv("ZRB_LLM_CONTEXT_ENRICHMENT_PROMPT", None)
|
342
|
-
|
343
339
|
@property
|
344
340
|
def LLM_SUMMARIZE_HISTORY(self) -> bool:
|
345
341
|
return to_boolean(os.getenv("ZRB_LLM_SUMMARIZE_HISTORY", "true"))
|
@@ -348,14 +344,6 @@ class Config:
|
|
348
344
|
def LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD(self) -> int:
|
349
345
|
return int(os.getenv("ZRB_LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD", "20000"))
|
350
346
|
|
351
|
-
@property
|
352
|
-
def LLM_ENRICH_CONTEXT(self) -> bool:
|
353
|
-
return to_boolean(os.getenv("ZRB_LLM_ENRICH_CONTEXT", "true"))
|
354
|
-
|
355
|
-
@property
|
356
|
-
def LLM_CONTEXT_ENRICHMENT_TOKEN_THRESHOLD(self) -> int:
|
357
|
-
return int(os.getenv("ZRB_LLM_CONTEXT_ENRICHMENT_TOKEN_THRESHOLD", "20000"))
|
358
|
-
|
359
347
|
@property
|
360
348
|
def LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_THRESHOLD(self) -> int:
|
361
349
|
return int(os.getenv("ZRB_LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_LIMIT", "35000"))
|
@@ -445,5 +433,13 @@ class Config:
|
|
445
433
|
{"VERSION": self.VERSION},
|
446
434
|
)
|
447
435
|
|
436
|
+
@property
|
437
|
+
def LLM_CONTEXTUAL_NOTE_FILE(self) -> str:
|
438
|
+
return os.getenv("LLM_CONTEXTUAL_NOTE_FILE", "ZRB_README.md")
|
439
|
+
|
440
|
+
@property
|
441
|
+
def LLM_LONG_TERM_NOTE_PATH(self) -> str:
|
442
|
+
return os.getenv("LLM_LONG_TERM_NOTE_PATH", "~/ZRB_GLOBAL_README.md")
|
443
|
+
|
448
444
|
|
449
445
|
CFG = Config()
|
zrb/config/llm_config.py
CHANGED
@@ -34,13 +34,22 @@ _DEFAULT_INTERACTIVE_SYSTEM_PROMPT = (
|
|
34
34
|
" * **CRITICAL:** Immediately after execution, you MUST use a tool "
|
35
35
|
"to verify the outcome (e.g., after `write_file`, use `read_file`; "
|
36
36
|
"after `rm`, use `ls` to confirm absence).\n\n"
|
37
|
-
"4. **Report Results:**\n"
|
38
|
-
" * Provide a concise summary of the action taken
|
39
|
-
"
|
40
|
-
"
|
41
|
-
"
|
42
|
-
"
|
43
|
-
"
|
37
|
+
"4. **Report Results and Handle Errors:**\n"
|
38
|
+
" * **On Success:** Provide a concise summary of the action taken "
|
39
|
+
"and explicitly state how you verified it.\n"
|
40
|
+
" * **On Failure (The Debugging Loop):** If a tool call fails, you "
|
41
|
+
"MUST NOT give up. Instead, you will enter a debugging loop:\n"
|
42
|
+
" 1. **Analyze:** Scrutinize the complete error message, "
|
43
|
+
"including any `stdout` and `stderr`.\n"
|
44
|
+
" 2. **Hypothesize:** State a clear, specific hypothesis about "
|
45
|
+
"the root cause of the error.\n"
|
46
|
+
" 3. **Act:** Propose a concrete, single next step to fix the "
|
47
|
+
"issue. This could be running a command with different parameters, "
|
48
|
+
"modifying a file, or using another tool to gather more context.\n\n"
|
49
|
+
"---\n"
|
50
|
+
"**FINAL REMINDER:** Your last step before responding MUST be to ensure "
|
51
|
+
"you have followed the Execute and Verify (E+V) loop. Do not "
|
52
|
+
"hallucinate verifications."
|
44
53
|
).strip()
|
45
54
|
|
46
55
|
_DEFAULT_SYSTEM_PROMPT = (
|
@@ -50,32 +59,36 @@ _DEFAULT_SYSTEM_PROMPT = (
|
|
50
59
|
"1. **Plan:** Internally devise a step-by-step plan. This plan MUST "
|
51
60
|
"include verification steps for each action.\n\n"
|
52
61
|
"2. **Assess and Decide:** Before executing, you MUST evaluate the risk of "
|
53
|
-
"your plan. For any destructive actions
|
54
|
-
"
|
55
|
-
"
|
62
|
+
"your plan. For any destructive actions, consider the command's nature "
|
63
|
+
"and target. Based on your assessment, decide the appropriate course of "
|
64
|
+
"action:\n"
|
56
65
|
" * **Low/Moderate Risk:** Proceed directly.\n"
|
57
66
|
" * **High Risk:** Refuse to execute, state your plan, and explain "
|
58
67
|
"the risk to the user.\n"
|
59
|
-
" * **Extreme Risk
|
60
|
-
"
|
61
|
-
"3. **Execute and Verify (The E+V Loop):**\n"
|
68
|
+
" * **Extreme Risk:** Refuse and explain the danger.\n\n"
|
69
|
+
"3. **Execute and Verify (The E+V Loop):\n"
|
62
70
|
" * Execute each step of your plan.\n"
|
63
71
|
" * **CRITICAL:** After each step, you MUST use a tool to verify "
|
64
72
|
"the outcome (e.g., check exit codes, read back file contents).\n\n"
|
65
|
-
"4. **Report Final Outcome
|
66
|
-
" * Provide a concise summary of the result
|
67
|
-
"
|
68
|
-
" *
|
69
|
-
"
|
73
|
+
"4. **Report Final Outcome:\n"
|
74
|
+
" * **On Success:** Provide a concise summary of the result and "
|
75
|
+
"explicitly state how you verified the final state.\n"
|
76
|
+
" * **On Failure:** Report the complete error, including `stdout` "
|
77
|
+
"and `stderr`. Analyze the error and provide a corrected command or a "
|
78
|
+
"clear explanation of the root cause.\n\n"
|
70
79
|
"---\n"
|
71
80
|
"**FINAL REMINDER:** Your last step before responding MUST be to ensure "
|
72
|
-
"you have followed the Execute and Verify (E+V) loop.
|
73
|
-
"
|
74
|
-
"corresponding verification tool call. Do not hallucinate verifications."
|
81
|
+
"you have followed the Execute and Verify (E+V) loop. Do not "
|
82
|
+
"hallucinate verifications."
|
75
83
|
).strip()
|
76
84
|
|
77
85
|
_DEFAULT_SPECIAL_INSTRUCTION_PROMPT = (
|
78
86
|
"## Guiding Principles\n"
|
87
|
+
"- **Clarify and Scope First:** Before undertaking any complex task (like "
|
88
|
+
"writing a new feature or a large test suite), you MUST ensure the request "
|
89
|
+
"is not ambiguous. If it is, ask clarifying questions. Propose a concise "
|
90
|
+
"plan or scope and ask for user approval before proceeding. Do not start a "
|
91
|
+
"multi-step task on a vague request.\n"
|
79
92
|
"- **Safety First:** Never run commands that are destructive or could "
|
80
93
|
"compromise the system without explicit user confirmation. When in "
|
81
94
|
"doubt, ask.\n"
|
@@ -84,6 +97,17 @@ _DEFAULT_SPECIAL_INSTRUCTION_PROMPT = (
|
|
84
97
|
"conventions.\n"
|
85
98
|
"- **Efficiency:** Use your tools to get the job done with the minimum "
|
86
99
|
"number of steps. Combine commands where possible.\n\n"
|
100
|
+
"## Critical Prohibitions\n"
|
101
|
+
"- **NEVER Assume Dependencies:** Do not use a library or framework unless "
|
102
|
+
"you have first verified it is an existing project dependency (e.g., in "
|
103
|
+
"`package.json`, `requirements.txt`).\n"
|
104
|
+
"- **NEVER Invent Conventions:** You MUST follow the existing conventions "
|
105
|
+
"discovered during your context-gathering phase. Do not introduce a new "
|
106
|
+
"style or pattern without a very good reason and, ideally, user "
|
107
|
+
"confirmation.\n"
|
108
|
+
"- **NEVER Commit Without Verification:** Do not use `git commit` until you "
|
109
|
+
"have staged the changes and run the project's own verification steps "
|
110
|
+
"(tests, linter, build).\n\n"
|
87
111
|
"## Common Task Workflows\n\n"
|
88
112
|
"**File System Operations:**\n"
|
89
113
|
"1. **Analyze:** Before modifying, read the file or list the "
|
@@ -92,10 +116,24 @@ _DEFAULT_SPECIAL_INSTRUCTION_PROMPT = (
|
|
92
116
|
"3. **Verify:** Check that the file/directory now exists (or doesn't) in "
|
93
117
|
"its expected state.\n\n"
|
94
118
|
"**Code & Software Development:**\n"
|
95
|
-
"1. **CRITICAL: Gather Context First:** Before writing or modifying any
|
96
|
-
"you MUST gather context to ensure your changes are idiomatic and
|
97
|
-
"Do not make assumptions. Your primary goal is to fit into the
|
98
|
-
"project seamlessly.\n"
|
119
|
+
"1. **CRITICAL: Gather Context First:** Before writing or modifying any "
|
120
|
+
"code, you MUST gather context to ensure your changes are idiomatic and "
|
121
|
+
"correct. Do not make assumptions. Your primary goal is to fit into the "
|
122
|
+
"existing project seamlessly.\n"
|
123
|
+
" * **Project Structure & Dependencies:** Check for `README.md`, "
|
124
|
+
"`CONTRIBUTING.md`, `package.json`, `pyproject.toml`, `build.gradle`, "
|
125
|
+
"etc., to understand the project's stated goals, dependencies, and "
|
126
|
+
"scripts (for linting, testing, building).\n"
|
127
|
+
" * **Code Style & Conventions:** Look for configuration files like "
|
128
|
+
"`.eslintrc`, `.prettierrc`, `.flake8`, or `ruff.toml`. Analyze "
|
129
|
+
"surrounding source files to determine:\n"
|
130
|
+
" * **Naming Conventions:** (e.g., `camelCase` vs. `snake_case`).\n"
|
131
|
+
" * **Typing Style:** (e.g., `List` from `typing` vs. built-in "
|
132
|
+
"`list`).\n"
|
133
|
+
" * **Error Handling:** (e.g., custom exceptions, `try/except` "
|
134
|
+
"blocks, returning error codes).\n"
|
135
|
+
" * **Architectural Patterns:** (e.g., is there a service layer? "
|
136
|
+
"Are components organized by feature or by type?).\n"
|
99
137
|
" * **When writing a new test:** You MUST first read the full source "
|
100
138
|
"code of the module(s) you are testing. This will inform you about the "
|
101
139
|
"actual implementation, such as its logging methods, error handling, and "
|
@@ -108,65 +146,85 @@ _DEFAULT_SPECIAL_INSTRUCTION_PROMPT = (
|
|
108
146
|
"context you gathered.\n"
|
109
147
|
"3. **Implement:** Make the changes, strictly adhering to the patterns and "
|
110
148
|
"conventions discovered in step 1.\n"
|
111
|
-
"4. **Verify:** Run all relevant tests, linters, and build
|
112
|
-
"
|
113
|
-
"
|
149
|
+
"4. **Verify & Debug:** Run all relevant tests, linters, and build "
|
150
|
+
"commands. If a command fails, your immediate next action MUST be to "
|
151
|
+
"enter the **Debugging Loop**: analyze the complete error output (`stdout` "
|
152
|
+
"and `stderr`), hypothesize the root cause. Your next immediate action "
|
153
|
+
"MUST be to execute a single, concrete tool call that attempts to fix "
|
154
|
+
"the issue based on your hypothesis. Do not stop to ask the user for "
|
155
|
+
"confirmation. The goal is to resolve the error autonomously.\n\n"
|
114
156
|
"**Research & Analysis:**\n"
|
115
157
|
"1. **Clarify:** Understand the core question and the desired output "
|
116
158
|
"format.\n"
|
117
159
|
"2. **Search:** Use web search tools to gather information from multiple "
|
118
160
|
"reputable sources.\n"
|
119
161
|
"3. **Synthesize & Cite:** Present the information clearly. For factual "
|
120
|
-
"claims, cite the source URL
|
162
|
+
"claims, cite the source URL.\n\n"
|
163
|
+
"## Communicating with the User\n"
|
164
|
+
"- **Be Concise:** When reporting results, be brief. Focus on the outcome "
|
165
|
+
"and the verification step.\n"
|
166
|
+
"- **Explain 'Why,' Not Just 'What':** For complex changes or bug fixes, "
|
167
|
+
"briefly explain *why* the change was necessary (e.g., 'The previous code "
|
168
|
+
"was failing because it didn't handle null inputs. I've added a check to "
|
169
|
+
"prevent this.').\n"
|
170
|
+
"- **Structure Your Plans:** When you present a plan for approval, use a "
|
171
|
+
"numbered or bulleted list for clarity."
|
121
172
|
).strip()
|
122
173
|
|
123
174
|
|
124
175
|
_DEFAULT_SUMMARIZATION_PROMPT = (
|
125
|
-
"You are a Conversation Historian. Your
|
126
|
-
"
|
127
|
-
"
|
128
|
-
"
|
129
|
-
"
|
130
|
-
"1.
|
131
|
-
"
|
132
|
-
"
|
133
|
-
"
|
134
|
-
" -
|
135
|
-
"
|
136
|
-
"
|
137
|
-
"
|
138
|
-
"
|
139
|
-
"
|
140
|
-
"
|
141
|
-
"
|
142
|
-
"
|
143
|
-
"
|
144
|
-
"
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
"
|
150
|
-
"
|
151
|
-
"
|
152
|
-
"
|
153
|
-
"
|
154
|
-
"the `
|
155
|
-
"
|
156
|
-
"
|
157
|
-
"
|
158
|
-
"
|
159
|
-
"
|
160
|
-
"
|
161
|
-
"
|
162
|
-
"
|
163
|
-
"
|
164
|
-
"
|
165
|
-
"
|
166
|
-
"
|
167
|
-
"
|
168
|
-
"
|
169
|
-
"
|
176
|
+
"You are a meticulous Conversation Historian agent. Your purpose is to "
|
177
|
+
"process the conversation history and update the assistant's memory "
|
178
|
+
"using your available tools. You will be given the previous summary, "
|
179
|
+
"previous notes, and the latest conversation turns in JSON format.\n\n"
|
180
|
+
"Follow these steps:\n\n"
|
181
|
+
"1. **Analyze the Recent Conversation:** Review the `Recent Conversation "
|
182
|
+
"(JSON)` to understand what just happened. Identify key facts, user "
|
183
|
+
"intentions, decisions made, and the final outcomes of any tasks.\n\n"
|
184
|
+
"2. **Update Long-Term Note:**\n"
|
185
|
+
" - Read the existing `Long Term` note to understand what is already "
|
186
|
+
"known.\n"
|
187
|
+
" - Identify any new, stable, and globally relevant information from "
|
188
|
+
"the recent conversation. This includes user preferences, high-level "
|
189
|
+
"goals, or facts that will be true regardless of the current working "
|
190
|
+
"directory. Only extract facts.\n"
|
191
|
+
" - If you find such information, use the `write_long_term_note` tool "
|
192
|
+
"to save a concise, updated version of the note. Keep it brief and "
|
193
|
+
"factual.\n\n"
|
194
|
+
"3. **Update Contextual Note:**\n"
|
195
|
+
" - Read the existing `Contextual` note.\n"
|
196
|
+
" - Identify new information relevant *only* to the current project "
|
197
|
+
"or directory. This could be the file the user is working on, the "
|
198
|
+
"specific bug they are fixing, or the feature they are building. "
|
199
|
+
"This note might contain temporary context, and information should be "
|
200
|
+
"deleted once it is no longer relevant.\n"
|
201
|
+
" - Use the `write_contextual_note` tool to save a concise, updated "
|
202
|
+
"note about the current working context. This note should be focused on "
|
203
|
+
"the immediate task at hand.\n\n"
|
204
|
+
"4. **Update Narrative Summary:**\n"
|
205
|
+
" - Review the `Past Conversation` summary.\n"
|
206
|
+
" - Create a new, condensed narrative that integrates the key "
|
207
|
+
"outcomes and decisions from the recent conversation. Discard "
|
208
|
+
"conversational filler. The summary should be a brief story of the "
|
209
|
+
"project's progress.\n"
|
210
|
+
" - Use the `write_past_conversation_summary` tool to save this new "
|
211
|
+
"summary.\n\n"
|
212
|
+
"5. **Update Transcript:**\n"
|
213
|
+
" - **CRITICAL:** Your final and most important task is to create a "
|
214
|
+
"transcript of the last few turns (around 4 turns).\n"
|
215
|
+
" - From the `Recent Conversation (JSON)`, extract the messages with "
|
216
|
+
"the role `user` and `assistant`. Ignore roles `system` and `tool`.\n"
|
217
|
+
" - Format the extracted messages into a readable dialog. For example:\n"
|
218
|
+
" User: <content of user message>\n"
|
219
|
+
" Assistant: <content of assistant message>\n"
|
220
|
+
" - If an assistant message contains `tool_calls`, note it like this:\n"
|
221
|
+
" Assistant (calling tool <tool_name>): <content of assistant message>\n"
|
222
|
+
" - The content of the user and assistant messages MUST be copied "
|
223
|
+
"verbatim. DO NOT alter, shorten, or summarize them in any way.\n"
|
224
|
+
" - Use the `write_past_conversation_transcript` tool to save this "
|
225
|
+
"formatted dialog string.\n\n"
|
226
|
+
"Your primary goal is to use your tools to persist these four distinct "
|
227
|
+
"pieces of information accurately and concisely."
|
170
228
|
).strip()
|
171
229
|
|
172
230
|
|
@@ -293,14 +351,6 @@ class LLMConfig:
|
|
293
351
|
return CFG.LLM_SUMMARIZATION_PROMPT
|
294
352
|
return _DEFAULT_SUMMARIZATION_PROMPT
|
295
353
|
|
296
|
-
@property
|
297
|
-
def default_context_enrichment_prompt(self) -> str:
|
298
|
-
if self._default_context_enrichment_prompt is not None:
|
299
|
-
return self._default_context_enrichment_prompt
|
300
|
-
if CFG.LLM_CONTEXT_ENRICHMENT_PROMPT is not None:
|
301
|
-
return CFG.LLM_CONTEXT_ENRICHMENT_PROMPT
|
302
|
-
return _DEFAULT_CONTEXT_ENRICHMENT_PROMPT
|
303
|
-
|
304
354
|
@property
|
305
355
|
def default_model(self) -> "Model | str | None":
|
306
356
|
if self._default_model is not None:
|
@@ -327,18 +377,6 @@ class LLMConfig:
|
|
327
377
|
return self._default_history_summarization_token_threshold
|
328
378
|
return CFG.LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD
|
329
379
|
|
330
|
-
@property
|
331
|
-
def default_enrich_context(self) -> bool:
|
332
|
-
if self._default_enrich_context is not None:
|
333
|
-
return self._default_enrich_context
|
334
|
-
return CFG.LLM_ENRICH_CONTEXT
|
335
|
-
|
336
|
-
@property
|
337
|
-
def default_context_enrichment_token_threshold(self) -> int:
|
338
|
-
if self._default_context_enrichment_token_threshold is not None:
|
339
|
-
return self._default_context_enrichment_token_threshold
|
340
|
-
return CFG.LLM_CONTEXT_ENRICHMENT_TOKEN_THRESHOLD
|
341
|
-
|
342
380
|
def set_default_persona(self, persona: str):
|
343
381
|
self._default_persona = persona
|
344
382
|
|
@@ -354,9 +392,6 @@ class LLMConfig:
|
|
354
392
|
def set_default_summarization_prompt(self, summarization_prompt: str):
|
355
393
|
self._default_summarization_prompt = summarization_prompt
|
356
394
|
|
357
|
-
def set_default_context_enrichment_prompt(self, context_enrichment_prompt: str):
|
358
|
-
self._default_context_enrichment_prompt = context_enrichment_prompt
|
359
|
-
|
360
395
|
def set_default_model_name(self, model_name: str):
|
361
396
|
self._default_model_name = model_name
|
362
397
|
|
@@ -382,16 +417,6 @@ class LLMConfig:
|
|
382
417
|
history_summarization_token_threshold
|
383
418
|
)
|
384
419
|
|
385
|
-
def set_default_enrich_context(self, enrich_context: bool):
|
386
|
-
self._default_enrich_context = enrich_context
|
387
|
-
|
388
|
-
def set_default_context_enrichment_token_threshold(
|
389
|
-
self, context_enrichment_token_threshold: int
|
390
|
-
):
|
391
|
-
self._default_context_enrichment_token_threshold = (
|
392
|
-
context_enrichment_token_threshold
|
393
|
-
)
|
394
|
-
|
395
420
|
def set_default_model_settings(self, model_settings: "ModelSettings"):
|
396
421
|
self._default_model_settings = model_settings
|
397
422
|
|
zrb/config/llm_rate_limitter.py
CHANGED
@@ -9,8 +9,19 @@ from zrb.config.config import CFG
|
|
9
9
|
|
10
10
|
|
11
11
|
def _estimate_token(text: str) -> int:
|
12
|
-
|
13
|
-
|
12
|
+
"""
|
13
|
+
Estimates the number of tokens in a given text.
|
14
|
+
Tries to use the 'gpt-4o' model's tokenizer for an accurate count.
|
15
|
+
If the tokenizer is unavailable (e.g., due to network issues),
|
16
|
+
it falls back to a heuristic of 4 characters per token.
|
17
|
+
"""
|
18
|
+
try:
|
19
|
+
# Primary method: Use tiktoken for an accurate count
|
20
|
+
enc = tiktoken.encoding_for_model("gpt-4o")
|
21
|
+
return len(enc.encode(text))
|
22
|
+
except Exception:
|
23
|
+
# Fallback method: Heuristic (4 characters per token)
|
24
|
+
return len(text) // 4
|
14
25
|
|
15
26
|
|
16
27
|
class LLMRateLimiter:
|