zrb 1.8.15__py3-none-any.whl → 1.9.0__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/chat_session.py +16 -11
- zrb/llm_config.py +132 -165
- zrb/task/any_task.py +6 -9
- zrb/task/llm/agent.py +26 -33
- zrb/task/llm/config.py +4 -7
- zrb/task/llm/context.py +0 -44
- zrb/task/llm/context_enrichment.py +44 -81
- zrb/task/llm/error.py +2 -4
- zrb/task/llm/history.py +19 -11
- zrb/task/llm/history_summarization.py +46 -69
- zrb/task/llm/print_node.py +10 -8
- zrb/task/llm/prompt.py +12 -19
- zrb/task/llm/tool_wrapper.py +2 -4
- zrb/task/llm_task.py +52 -60
- {zrb-1.8.15.dist-info → zrb-1.9.0.dist-info}/METADATA +1 -1
- {zrb-1.8.15.dist-info → zrb-1.9.0.dist-info}/RECORD +18 -18
- {zrb-1.8.15.dist-info → zrb-1.9.0.dist-info}/WHEEL +0 -0
- {zrb-1.8.15.dist-info → zrb-1.9.0.dist-info}/entry_points.txt +0 -0
zrb/task/llm/context.py
CHANGED
@@ -1,14 +1,9 @@
|
|
1
1
|
import datetime
|
2
|
-
import inspect
|
3
2
|
import os
|
4
3
|
import platform
|
5
4
|
import re
|
6
|
-
from collections.abc import Callable
|
7
5
|
from typing import Any
|
8
6
|
|
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
|
12
7
|
from zrb.util.file import read_dir, read_file_with_line_numbers
|
13
8
|
|
14
9
|
|
@@ -61,42 +56,3 @@ def extract_default_context(user_message: str) -> tuple[str, dict[str, Any]]:
|
|
61
56
|
}
|
62
57
|
|
63
58
|
return modified_user_message, context
|
64
|
-
|
65
|
-
|
66
|
-
def get_conversation_context(
|
67
|
-
ctx: AnyContext,
|
68
|
-
conversation_context_attr: (
|
69
|
-
dict[str, Any] | Callable[[AnySharedContext], dict[str, Any]] | None
|
70
|
-
),
|
71
|
-
) -> dict[str, Any]:
|
72
|
-
"""
|
73
|
-
Retrieves the conversation context.
|
74
|
-
If a value in the context dict is callable, it executes it with ctx.
|
75
|
-
"""
|
76
|
-
raw_context = get_attr(ctx, conversation_context_attr, {}, auto_render=False)
|
77
|
-
if not isinstance(raw_context, dict):
|
78
|
-
ctx.log_warning(
|
79
|
-
f"Conversation context resolved to type {type(raw_context)}, "
|
80
|
-
"expected dict. Returning empty context."
|
81
|
-
)
|
82
|
-
return {}
|
83
|
-
# If conversation_context contains callable value, execute them.
|
84
|
-
processed_context: dict[str, Any] = {}
|
85
|
-
for key, value in raw_context.items():
|
86
|
-
if callable(value):
|
87
|
-
try:
|
88
|
-
# Check if the callable expects 'ctx'
|
89
|
-
sig = inspect.signature(value)
|
90
|
-
if "ctx" in sig.parameters:
|
91
|
-
processed_context[key] = value(ctx)
|
92
|
-
else:
|
93
|
-
processed_context[key] = value()
|
94
|
-
except Exception as e:
|
95
|
-
ctx.log_warning(
|
96
|
-
f"Error executing callable for context key '{key}': {e}. "
|
97
|
-
"Skipping."
|
98
|
-
)
|
99
|
-
processed_context[key] = None
|
100
|
-
else:
|
101
|
-
processed_context[key] = value
|
102
|
-
return processed_context
|
@@ -1,8 +1,6 @@
|
|
1
1
|
import json
|
2
2
|
import traceback
|
3
|
-
from typing import TYPE_CHECKING
|
4
|
-
|
5
|
-
from pydantic import BaseModel
|
3
|
+
from typing import TYPE_CHECKING
|
6
4
|
|
7
5
|
from zrb.attr.type import BoolAttr, IntAttr
|
8
6
|
from zrb.context.any_context import AnyContext
|
@@ -20,95 +18,63 @@ from zrb.util.cli.style import stylize_faint
|
|
20
18
|
if TYPE_CHECKING:
|
21
19
|
from pydantic_ai.models import Model
|
22
20
|
from pydantic_ai.settings import ModelSettings
|
23
|
-
else:
|
24
|
-
Model = Any
|
25
|
-
ModelSettings = Any
|
26
|
-
|
27
|
-
|
28
|
-
class EnrichmentConfig(BaseModel):
|
29
|
-
model_config = {"arbitrary_types_allowed": True}
|
30
|
-
model: Model | str | None = None
|
31
|
-
settings: ModelSettings | None = None
|
32
|
-
prompt: str
|
33
|
-
retries: int = 3
|
34
|
-
|
35
|
-
|
36
|
-
class EnrichmentResult(BaseModel):
|
37
|
-
response: dict[str, Any] # or further decompose as needed
|
38
21
|
|
39
22
|
|
40
23
|
async def enrich_context(
|
41
24
|
ctx: AnyContext,
|
42
|
-
|
43
|
-
|
25
|
+
model: "Model | str | None",
|
26
|
+
settings: "ModelSettings | None",
|
27
|
+
prompt: str,
|
28
|
+
previous_long_term_context: str,
|
44
29
|
history_list: ListOfDict,
|
45
30
|
rate_limitter: LLMRateLimiter | None = None,
|
46
|
-
|
47
|
-
|
31
|
+
retries: int = 3,
|
32
|
+
) -> str:
|
33
|
+
"""Runs an LLM call to update the long-term context and returns the new context string."""
|
48
34
|
from pydantic_ai import Agent
|
49
35
|
|
50
36
|
ctx.log_info("Attempting to enrich conversation context...")
|
51
|
-
#
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
[
|
59
|
-
"Extract context from the following conversation info.",
|
60
|
-
"Extract only contexts that will be relevant across multiple conversations, like", # noqa
|
61
|
-
"- user name",
|
62
|
-
"- user hobby",
|
63
|
-
"- user's long life goal",
|
64
|
-
"- standard/SOP",
|
65
|
-
"- etc.",
|
66
|
-
"Always maintain the relevant context and remove the irrelevant ones.",
|
67
|
-
"Restructure the context in a helpful way",
|
68
|
-
"Keep the context small",
|
69
|
-
f"Existing Context: {context_json}",
|
70
|
-
f"Conversation History: {history_json}",
|
71
|
-
]
|
72
|
-
)
|
73
|
-
except Exception as e:
|
74
|
-
ctx.log_warning(f"Error formatting context/history for enrichment: {e}")
|
75
|
-
return conversation_context # Return original context if formatting fails
|
76
|
-
|
37
|
+
# Construct the user prompt according to the new prompt format
|
38
|
+
user_prompt = json.dumps(
|
39
|
+
{
|
40
|
+
"previous_long_term_context": previous_long_term_context,
|
41
|
+
"recent_conversation_history": history_list,
|
42
|
+
}
|
43
|
+
)
|
77
44
|
enrichment_agent = Agent(
|
78
|
-
model=
|
79
|
-
system_prompt=
|
80
|
-
model_settings=
|
81
|
-
retries=
|
82
|
-
output_type=EnrichmentResult,
|
45
|
+
model=model,
|
46
|
+
system_prompt=prompt,
|
47
|
+
model_settings=settings,
|
48
|
+
retries=retries,
|
83
49
|
)
|
84
50
|
|
85
51
|
try:
|
86
|
-
ctx.print(stylize_faint("
|
52
|
+
ctx.print(stylize_faint("💡 Enrich Context"), plain=True)
|
87
53
|
enrichment_run = await run_agent_iteration(
|
88
54
|
ctx=ctx,
|
89
55
|
agent=enrichment_agent,
|
90
|
-
user_prompt=
|
91
|
-
history_list=[], # Enrichment agent
|
56
|
+
user_prompt=user_prompt,
|
57
|
+
history_list=[], # Enrichment agent works off the prompt, not history
|
92
58
|
rate_limitter=rate_limitter,
|
93
59
|
)
|
94
60
|
if enrichment_run and enrichment_run.result.output:
|
95
|
-
|
61
|
+
new_long_term_context = str(enrichment_run.result.output)
|
96
62
|
usage = enrichment_run.result.usage()
|
97
|
-
ctx.print(
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
f"Updated conversation context: {json.dumps(conversation_context)}"
|
105
|
-
)
|
63
|
+
ctx.print(
|
64
|
+
stylize_faint(f"💡 Context Enrichment Token: {usage}"), plain=True
|
65
|
+
)
|
66
|
+
ctx.print(plain=True)
|
67
|
+
ctx.log_info("Context enriched based on history.")
|
68
|
+
ctx.log_info(f"Updated long-term context:\n{new_long_term_context}")
|
69
|
+
return new_long_term_context
|
106
70
|
else:
|
107
|
-
ctx.log_warning("Context enrichment returned no data")
|
71
|
+
ctx.log_warning("Context enrichment returned no data.")
|
108
72
|
except Exception as e:
|
109
73
|
ctx.log_warning(f"Error during context enrichment LLM call: {e}")
|
110
74
|
traceback.print_exc()
|
111
|
-
|
75
|
+
|
76
|
+
# Return the original context if enrichment fails
|
77
|
+
return previous_long_term_context
|
112
78
|
|
113
79
|
|
114
80
|
def get_context_enrichment_threshold(
|
@@ -121,7 +87,6 @@ def get_context_enrichment_threshold(
|
|
121
87
|
return get_int_attr(
|
122
88
|
ctx,
|
123
89
|
context_enrichment_threshold_attr,
|
124
|
-
# Use llm_config default if attribute is None
|
125
90
|
llm_config.default_context_enrichment_threshold,
|
126
91
|
auto_render=render_context_enrichment_threshold,
|
127
92
|
)
|
@@ -136,7 +101,7 @@ def get_context_enrichment_threshold(
|
|
136
101
|
def should_enrich_context(
|
137
102
|
ctx: AnyContext,
|
138
103
|
history_list: ListOfDict,
|
139
|
-
should_enrich_context_attr: BoolAttr | None,
|
104
|
+
should_enrich_context_attr: BoolAttr | None,
|
140
105
|
render_enrich_context: bool,
|
141
106
|
context_enrichment_threshold_attr: IntAttr | None,
|
142
107
|
render_context_enrichment_threshold: bool,
|
@@ -165,16 +130,16 @@ def should_enrich_context(
|
|
165
130
|
async def maybe_enrich_context(
|
166
131
|
ctx: AnyContext,
|
167
132
|
history_list: ListOfDict,
|
168
|
-
|
133
|
+
long_term_context: str,
|
169
134
|
should_enrich_context_attr: BoolAttr | None,
|
170
135
|
render_enrich_context: bool,
|
171
136
|
context_enrichment_threshold_attr: IntAttr | None,
|
172
137
|
render_context_enrichment_threshold: bool,
|
173
|
-
model: str | Model | None,
|
174
|
-
model_settings: ModelSettings | None,
|
138
|
+
model: "str | Model | None",
|
139
|
+
model_settings: "ModelSettings | None",
|
175
140
|
context_enrichment_prompt: str,
|
176
141
|
rate_limitter: LLMRateLimiter | None = None,
|
177
|
-
) ->
|
142
|
+
) -> str:
|
178
143
|
"""Enriches context based on history if enabled and threshold met."""
|
179
144
|
shorten_history_list = replace_system_prompt_in_history_list(history_list)
|
180
145
|
if should_enrich_context(
|
@@ -187,13 +152,11 @@ async def maybe_enrich_context(
|
|
187
152
|
):
|
188
153
|
return await enrich_context(
|
189
154
|
ctx=ctx,
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
),
|
195
|
-
conversation_context=conversation_context,
|
155
|
+
model=model,
|
156
|
+
settings=model_settings,
|
157
|
+
prompt=context_enrichment_prompt,
|
158
|
+
previous_long_term_context=long_term_context,
|
196
159
|
history_list=shorten_history_list,
|
197
160
|
rate_limitter=rate_limitter,
|
198
161
|
)
|
199
|
-
return
|
162
|
+
return long_term_context
|
zrb/task/llm/error.py
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
import json
|
2
|
-
from typing import TYPE_CHECKING,
|
2
|
+
from typing import TYPE_CHECKING, Optional
|
3
3
|
|
4
4
|
from pydantic import BaseModel
|
5
5
|
|
6
6
|
if TYPE_CHECKING:
|
7
7
|
from openai import APIError
|
8
|
-
else:
|
9
|
-
APIError = Any
|
10
8
|
|
11
9
|
|
12
10
|
# Define a structured error model for tool execution failures
|
@@ -17,7 +15,7 @@ class ToolExecutionError(BaseModel):
|
|
17
15
|
details: Optional[str] = None
|
18
16
|
|
19
17
|
|
20
|
-
def extract_api_error_details(error: APIError) -> str:
|
18
|
+
def extract_api_error_details(error: "APIError") -> str:
|
21
19
|
"""Extract detailed error information from an APIError."""
|
22
20
|
details = f"{error.message}"
|
23
21
|
# Try to parse the error body as JSON
|
zrb/task/llm/history.py
CHANGED
@@ -4,7 +4,7 @@ from collections.abc import Callable
|
|
4
4
|
from copy import deepcopy
|
5
5
|
from typing import Any, Optional
|
6
6
|
|
7
|
-
from pydantic import BaseModel
|
7
|
+
from pydantic import BaseModel, Field
|
8
8
|
|
9
9
|
from zrb.attr.type import StrAttr
|
10
10
|
from zrb.context.any_context import AnyContext
|
@@ -17,8 +17,18 @@ from zrb.util.run import run_async
|
|
17
17
|
|
18
18
|
# Define the new ConversationHistoryData model
|
19
19
|
class ConversationHistoryData(BaseModel):
|
20
|
-
|
21
|
-
|
20
|
+
long_term_context: str = Field(
|
21
|
+
default="",
|
22
|
+
description="A markdown-formatted string containing curated, long-term context.",
|
23
|
+
)
|
24
|
+
conversation_summary: str = Field(
|
25
|
+
default="",
|
26
|
+
description="A free-text summary of the conversation history.",
|
27
|
+
)
|
28
|
+
history: ListOfDict = Field(
|
29
|
+
default_factory=list,
|
30
|
+
description="The recent, un-summarized conversation history.",
|
31
|
+
)
|
22
32
|
|
23
33
|
@classmethod
|
24
34
|
async def read_from_sources(
|
@@ -69,19 +79,17 @@ class ConversationHistoryData(BaseModel):
|
|
69
79
|
try:
|
70
80
|
if isinstance(data, cls):
|
71
81
|
return data # Already a valid instance
|
72
|
-
if isinstance(data, dict)
|
73
|
-
#
|
74
|
-
# Ensure context exists, even if empty
|
75
|
-
data.setdefault("context", {})
|
82
|
+
if isinstance(data, dict):
|
83
|
+
# This handles both the new format and the old {'context': ..., 'history': ...}
|
76
84
|
return cls.model_validate(data)
|
77
85
|
elif isinstance(data, list):
|
78
|
-
# Handle old format (just a list) - wrap it
|
86
|
+
# Handle very old format (just a list) - wrap it
|
79
87
|
ctx.log_warning(
|
80
|
-
f"History from {source} contains
|
81
|
-
"Wrapping it into the new structure
|
88
|
+
f"History from {source} contains legacy list format. "
|
89
|
+
"Wrapping it into the new structure. "
|
82
90
|
"Consider updating the source format."
|
83
91
|
)
|
84
|
-
return cls(history=data
|
92
|
+
return cls(history=data)
|
85
93
|
else:
|
86
94
|
ctx.log_warning(
|
87
95
|
f"History data from {source} has unexpected format "
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import json
|
2
|
-
|
3
|
-
|
4
|
-
from pydantic import BaseModel
|
2
|
+
import traceback
|
3
|
+
from typing import TYPE_CHECKING
|
5
4
|
|
6
5
|
from zrb.attr.type import BoolAttr, IntAttr
|
7
6
|
from zrb.context.any_context import AnyContext
|
@@ -19,9 +18,6 @@ from zrb.util.cli.style import stylize_faint
|
|
19
18
|
if TYPE_CHECKING:
|
20
19
|
from pydantic_ai.models import Model
|
21
20
|
from pydantic_ai.settings import ModelSettings
|
22
|
-
else:
|
23
|
-
Model = Any
|
24
|
-
ModelSettings = Any
|
25
21
|
|
26
22
|
|
27
23
|
def get_history_summarization_threshold(
|
@@ -34,7 +30,6 @@ def get_history_summarization_threshold(
|
|
34
30
|
return get_int_attr(
|
35
31
|
ctx,
|
36
32
|
history_summarization_threshold_attr,
|
37
|
-
# Use llm_config default if attribute is None
|
38
33
|
llm_config.default_history_summarization_threshold,
|
39
34
|
auto_render=render_history_summarization_threshold,
|
40
35
|
)
|
@@ -49,9 +44,9 @@ def get_history_summarization_threshold(
|
|
49
44
|
def should_summarize_history(
|
50
45
|
ctx: AnyContext,
|
51
46
|
history_list: ListOfDict,
|
52
|
-
should_summarize_history_attr: BoolAttr | None,
|
47
|
+
should_summarize_history_attr: BoolAttr | None,
|
53
48
|
render_summarize_history: bool,
|
54
|
-
history_summarization_threshold_attr: IntAttr | None,
|
49
|
+
history_summarization_threshold_attr: IntAttr | None,
|
55
50
|
render_history_summarization_threshold: bool,
|
56
51
|
) -> bool:
|
57
52
|
"""Determines if history summarization should occur based on length and config."""
|
@@ -68,91 +63,76 @@ def should_summarize_history(
|
|
68
63
|
return get_bool_attr(
|
69
64
|
ctx,
|
70
65
|
should_summarize_history_attr,
|
71
|
-
# Use llm_config default if attribute is None
|
72
66
|
llm_config.default_summarize_history,
|
73
67
|
auto_render=render_summarize_history,
|
74
68
|
)
|
75
69
|
|
76
70
|
|
77
|
-
class SummarizationConfig(BaseModel):
|
78
|
-
model_config = {"arbitrary_types_allowed": True}
|
79
|
-
model: Model | str | None = None
|
80
|
-
settings: ModelSettings | None = None
|
81
|
-
prompt: str
|
82
|
-
retries: int = 3
|
83
|
-
|
84
|
-
|
85
71
|
async def summarize_history(
|
86
72
|
ctx: AnyContext,
|
87
|
-
|
88
|
-
|
73
|
+
model: "Model | str | None",
|
74
|
+
settings: "ModelSettings | None",
|
75
|
+
prompt: str,
|
76
|
+
previous_summary: str,
|
89
77
|
history_list: ListOfDict,
|
90
78
|
rate_limitter: LLMRateLimiter | None = None,
|
91
|
-
|
92
|
-
|
79
|
+
retries: int = 3,
|
80
|
+
) -> str:
|
81
|
+
"""Runs an LLM call to update the conversation summary."""
|
93
82
|
from pydantic_ai import Agent
|
94
83
|
|
95
84
|
ctx.log_info("Attempting to summarize conversation history...")
|
96
|
-
|
85
|
+
# Construct the user prompt for the summarization agent
|
86
|
+
user_prompt = json.dumps(
|
87
|
+
{"previous_summary": previous_summary, "recent_history": history_list}
|
88
|
+
)
|
97
89
|
summarization_agent = Agent(
|
98
|
-
model=
|
99
|
-
system_prompt=
|
100
|
-
model_settings=
|
101
|
-
retries=
|
90
|
+
model=model,
|
91
|
+
system_prompt=prompt,
|
92
|
+
model_settings=settings,
|
93
|
+
retries=retries,
|
102
94
|
)
|
103
95
|
|
104
|
-
# Prepare context and history for summarization prompt
|
105
96
|
try:
|
106
|
-
|
107
|
-
history_to_summarize_json = json.dumps(history_list)
|
108
|
-
summarization_user_prompt = "\n".join(
|
109
|
-
[
|
110
|
-
f"Current Context: {context_json}",
|
111
|
-
f"Conversation History to Summarize: {history_to_summarize_json}",
|
112
|
-
]
|
113
|
-
)
|
114
|
-
except Exception as e:
|
115
|
-
ctx.log_warning(f"Error formatting context/history for summarization: {e}")
|
116
|
-
return conversation_context # Return original context if formatting fails
|
117
|
-
|
118
|
-
try:
|
119
|
-
ctx.print(stylize_faint("[Summarization Triggered]"), plain=True)
|
97
|
+
ctx.print(stylize_faint("📝 Summarize"), plain=True)
|
120
98
|
summary_run = await run_agent_iteration(
|
121
99
|
ctx=ctx,
|
122
100
|
agent=summarization_agent,
|
123
|
-
user_prompt=
|
124
|
-
history_list=[],
|
101
|
+
user_prompt=user_prompt,
|
102
|
+
history_list=[],
|
125
103
|
rate_limitter=rate_limitter,
|
126
104
|
)
|
127
105
|
if summary_run and summary_run.result.output:
|
128
|
-
|
106
|
+
new_summary = str(summary_run.result.output)
|
129
107
|
usage = summary_run.result.usage()
|
130
|
-
ctx.print(stylize_faint(f"
|
131
|
-
|
132
|
-
|
133
|
-
ctx.log_info("
|
134
|
-
|
108
|
+
ctx.print(stylize_faint(f"📝 Summarization Token: {usage}"), plain=True)
|
109
|
+
ctx.print(plain=True)
|
110
|
+
ctx.log_info("History summarized and updated.")
|
111
|
+
ctx.log_info(f"New conversation summary:\n{new_summary}")
|
112
|
+
return new_summary
|
135
113
|
else:
|
136
114
|
ctx.log_warning("History summarization failed or returned no data.")
|
137
115
|
except Exception as e:
|
138
116
|
ctx.log_warning(f"Error during history summarization: {e}")
|
117
|
+
traceback.print_exc()
|
139
118
|
|
140
|
-
|
119
|
+
# Return the original summary if summarization fails
|
120
|
+
return previous_summary
|
141
121
|
|
142
122
|
|
143
123
|
async def maybe_summarize_history(
|
144
124
|
ctx: AnyContext,
|
145
125
|
history_list: ListOfDict,
|
146
|
-
|
147
|
-
should_summarize_history_attr: BoolAttr | None,
|
126
|
+
conversation_summary: str,
|
127
|
+
should_summarize_history_attr: BoolAttr | None,
|
148
128
|
render_summarize_history: bool,
|
149
|
-
history_summarization_threshold_attr: IntAttr | None,
|
129
|
+
history_summarization_threshold_attr: IntAttr | None,
|
150
130
|
render_history_summarization_threshold: bool,
|
151
|
-
model: str | Model | None,
|
152
|
-
model_settings: ModelSettings | None,
|
131
|
+
model: "str | Model | None",
|
132
|
+
model_settings: "ModelSettings | None",
|
153
133
|
summarization_prompt: str,
|
154
134
|
rate_limitter: LLMRateLimiter | None = None,
|
155
|
-
) -> tuple[ListOfDict,
|
135
|
+
) -> tuple[ListOfDict, str]:
|
156
136
|
"""Summarizes history and updates context if enabled and threshold met."""
|
157
137
|
shorten_history_list = replace_system_prompt_in_history_list(history_list)
|
158
138
|
if should_summarize_history(
|
@@ -163,18 +143,15 @@ async def maybe_summarize_history(
|
|
163
143
|
history_summarization_threshold_attr,
|
164
144
|
render_history_summarization_threshold,
|
165
145
|
):
|
166
|
-
|
167
|
-
updated_context = await summarize_history(
|
146
|
+
new_summary = await summarize_history(
|
168
147
|
ctx=ctx,
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
conversation_context=conversation_context,
|
175
|
-
history_list=shorten_history_list, # Pass the full list for context
|
148
|
+
model=model,
|
149
|
+
settings=model_settings,
|
150
|
+
prompt=summarization_prompt,
|
151
|
+
previous_summary=conversation_summary,
|
152
|
+
history_list=shorten_history_list,
|
176
153
|
rate_limitter=rate_limitter,
|
177
154
|
)
|
178
|
-
#
|
179
|
-
return [],
|
180
|
-
return history_list,
|
155
|
+
# After summarization, the history is cleared and replaced by the new summary
|
156
|
+
return [], new_summary
|
157
|
+
return history_list, conversation_summary
|
zrb/task/llm/print_node.py
CHANGED
@@ -19,11 +19,11 @@ async def print_node(print_func: Callable, agent_run: Any, node: Any):
|
|
19
19
|
|
20
20
|
if Agent.is_user_prompt_node(node):
|
21
21
|
# A user prompt node => The user has provided input
|
22
|
-
print_func(stylize_faint(f">> UserPromptNode: {node.user_prompt}"))
|
22
|
+
print_func(stylize_faint(f" >> UserPromptNode: {node.user_prompt}"))
|
23
23
|
elif Agent.is_model_request_node(node):
|
24
24
|
# A model request node => We can stream tokens from the model's request
|
25
25
|
print_func(
|
26
|
-
stylize_faint(">> ModelRequestNode: streaming partial request tokens")
|
26
|
+
stylize_faint(" >> ModelRequestNode: streaming partial request tokens")
|
27
27
|
)
|
28
28
|
async with node.stream(agent_run.ctx) as request_stream:
|
29
29
|
is_streaming = False
|
@@ -33,7 +33,7 @@ async def print_node(print_func: Callable, agent_run: Any, node: Any):
|
|
33
33
|
print_func("")
|
34
34
|
print_func(
|
35
35
|
stylize_faint(
|
36
|
-
f"[Request] Starting part {event.index}: {event.part!r}"
|
36
|
+
f" [Request] Starting part {event.index}: {event.part!r}"
|
37
37
|
),
|
38
38
|
)
|
39
39
|
is_streaming = False
|
@@ -53,7 +53,7 @@ async def print_node(print_func: Callable, agent_run: Any, node: Any):
|
|
53
53
|
if is_streaming:
|
54
54
|
print_func("")
|
55
55
|
print_func(
|
56
|
-
stylize_faint(f"[Result] tool_name={event.tool_name}"),
|
56
|
+
stylize_faint(f" [Result] tool_name={event.tool_name}"),
|
57
57
|
)
|
58
58
|
is_streaming = False
|
59
59
|
if is_streaming:
|
@@ -61,7 +61,9 @@ async def print_node(print_func: Callable, agent_run: Any, node: Any):
|
|
61
61
|
elif Agent.is_call_tools_node(node):
|
62
62
|
# A handle-response node => The model returned some data, potentially calls a tool
|
63
63
|
print_func(
|
64
|
-
stylize_faint(
|
64
|
+
stylize_faint(
|
65
|
+
" >> CallToolsNode: streaming partial response & tool usage"
|
66
|
+
)
|
65
67
|
)
|
66
68
|
async with node.stream(agent_run.ctx) as handle_stream:
|
67
69
|
async for event in handle_stream:
|
@@ -82,16 +84,16 @@ async def print_node(print_func: Callable, agent_run: Any, node: Any):
|
|
82
84
|
del event.part.args["_dummy"]
|
83
85
|
print_func(
|
84
86
|
stylize_faint(
|
85
|
-
f"[Tools] The LLM calls tool={event.part.tool_name!r} with args={event.part.args} (tool_call_id={event.part.tool_call_id!r})" # noqa
|
87
|
+
f" [Tools] The LLM calls tool={event.part.tool_name!r} with args={event.part.args} (tool_call_id={event.part.tool_call_id!r})" # noqa
|
86
88
|
)
|
87
89
|
)
|
88
90
|
elif isinstance(event, FunctionToolResultEvent):
|
89
91
|
print_func(
|
90
92
|
stylize_faint(
|
91
|
-
f"[Tools] Tool call {event.tool_call_id!r} returned => {event.result.content}" # noqa
|
93
|
+
f" [Tools] Tool call {event.tool_call_id!r} returned => {event.result.content}" # noqa
|
92
94
|
)
|
93
95
|
)
|
94
96
|
elif Agent.is_end_node(node):
|
95
97
|
# Once an End node is reached, the agent run is complete
|
96
|
-
print_func(stylize_faint("[End of Response]"))
|
98
|
+
print_func(stylize_faint(" [End of Response]"))
|
97
99
|
# print_func(stylize_faint(f"{agent_run.result.data}"))
|