agentic-blocks 0.1.24__py3-none-any.whl → 0.1.25__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.
- agentic_blocks/agent.py +16 -57
- agentic_blocks/agent_rich.py +169 -0
- agentic_blocks/utils/logger.py +14 -0
- agentic_blocks/utils/rich_logger.py +59 -0
- {agentic_blocks-0.1.24.dist-info → agentic_blocks-0.1.25.dist-info}/METADATA +1 -1
- agentic_blocks-0.1.25.dist-info/RECORD +15 -0
- agentic_blocks-0.1.24.dist-info/RECORD +0 -12
- {agentic_blocks-0.1.24.dist-info → agentic_blocks-0.1.25.dist-info}/WHEEL +0 -0
- {agentic_blocks-0.1.24.dist-info → agentic_blocks-0.1.25.dist-info}/licenses/LICENSE +0 -0
- {agentic_blocks-0.1.24.dist-info → agentic_blocks-0.1.25.dist-info}/top_level.txt +0 -0
agentic_blocks/agent.py
CHANGED
@@ -3,19 +3,10 @@ from agentic_blocks.utils.tools_utils import (
|
|
3
3
|
create_tool_registry,
|
4
4
|
execute_pending_tool_calls,
|
5
5
|
)
|
6
|
+
from agentic_blocks.utils.logger import get_logger
|
6
7
|
from agentic_blocks import call_llm, Messages
|
7
|
-
|
8
|
-
|
9
|
-
from rich.console import Console
|
10
|
-
from rich.console import Group
|
11
|
-
|
12
|
-
console = Console(
|
13
|
-
style="black on bright_white",
|
14
|
-
force_terminal=True,
|
15
|
-
width=None,
|
16
|
-
legacy_windows=False,
|
17
|
-
color_system="truecolor",
|
18
|
-
)
|
8
|
+
|
9
|
+
logger = get_logger(__name__)
|
19
10
|
|
20
11
|
|
21
12
|
class Agent:
|
@@ -23,7 +14,6 @@ class Agent:
|
|
23
14
|
self.system_prompt = system_prompt
|
24
15
|
self.tools = tools
|
25
16
|
self.tool_registry = create_tool_registry(tools)
|
26
|
-
self.panels = []
|
27
17
|
|
28
18
|
# Create nodes
|
29
19
|
self.llm_node = self._create_llm_node()
|
@@ -49,7 +39,12 @@ class Agent:
|
|
49
39
|
return messages
|
50
40
|
|
51
41
|
def exec(self, messages) -> Messages:
|
42
|
+
latest_message = messages.get_messages()[-1]
|
43
|
+
if latest_message["role"] == "user":
|
44
|
+
logger.info(f'message: "{latest_message["content"]}"')
|
45
|
+
|
52
46
|
response = call_llm(messages=messages, tools=self.tools)
|
47
|
+
# logger.info(f'response: "{response["content"] or "tool_calls"}"')
|
53
48
|
messages.add_response_message(response)
|
54
49
|
return messages
|
55
50
|
|
@@ -63,30 +58,19 @@ class Agent:
|
|
63
58
|
|
64
59
|
def _create_tool_node(self):
|
65
60
|
class ToolNode(Node):
|
66
|
-
def __init__(self, tool_registry
|
61
|
+
def __init__(self, tool_registry):
|
67
62
|
super().__init__()
|
68
63
|
self.tool_registry = tool_registry
|
69
|
-
self.agent = agent
|
70
64
|
|
71
65
|
def prep(self, shared):
|
72
66
|
return shared["messages"]
|
73
67
|
|
74
|
-
def exec(self, messages) -> Messages:
|
75
|
-
tool_calls = messages.get_pending_tool_calls()
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
# Format arguments nicely
|
80
|
-
if isinstance(tool_arguments, dict):
|
81
|
-
args_str = ", ".join(
|
82
|
-
[f"{k}={v}" for k, v in tool_arguments.items()]
|
68
|
+
def exec(self, messages: Messages) -> Messages:
|
69
|
+
tool_calls = messages.get_pending_tool_calls()
|
70
|
+
for tool_call in tool_calls:
|
71
|
+
logger.info(
|
72
|
+
f'tool_call: "{tool_call["tool_name"]}({tool_call["arguments"]})"'
|
83
73
|
)
|
84
|
-
formatted_call = f"{tool_name}({args_str})"
|
85
|
-
else:
|
86
|
-
formatted_call = f"{tool_name}({tool_arguments})"
|
87
|
-
|
88
|
-
tool_panel = self.agent.create_panel(formatted_call, "Tool Calls")
|
89
|
-
self.agent.panels.append(tool_panel)
|
90
74
|
|
91
75
|
tool_responses = execute_pending_tool_calls(
|
92
76
|
messages, self.tool_registry
|
@@ -97,7 +81,7 @@ class Agent:
|
|
97
81
|
def post(self, shared, prep_res, messages):
|
98
82
|
return "llm_node"
|
99
83
|
|
100
|
-
return ToolNode(self.tool_registry
|
84
|
+
return ToolNode(self.tool_registry)
|
101
85
|
|
102
86
|
def _create_answer_node(self):
|
103
87
|
class AnswerNode(Node):
|
@@ -110,6 +94,7 @@ class Agent:
|
|
110
94
|
|
111
95
|
def invoke(self, user_prompt: str) -> str:
|
112
96
|
messages = Messages(user_prompt=user_prompt)
|
97
|
+
logger.info(f'message: "{user_prompt}"')
|
113
98
|
if self.system_prompt:
|
114
99
|
messages.add_system_message(self.system_prompt)
|
115
100
|
|
@@ -117,29 +102,3 @@ class Agent:
|
|
117
102
|
self.flow.run(shared)
|
118
103
|
|
119
104
|
return shared["answer"]
|
120
|
-
|
121
|
-
def print_response(self, user_prompt: str, stream: bool = False):
|
122
|
-
# Reset panels and start with message
|
123
|
-
self.panels = []
|
124
|
-
message_panel = self.create_panel(user_prompt, "Message")
|
125
|
-
self.panels.append(message_panel)
|
126
|
-
|
127
|
-
# Always collect all panels first
|
128
|
-
response = self.invoke(user_prompt)
|
129
|
-
response_panel = self.create_panel(response, "Response")
|
130
|
-
self.panels.append(response_panel)
|
131
|
-
|
132
|
-
# Print all panels as a group (no gaps)
|
133
|
-
panel_group = Group(*self.panel)
|
134
|
-
console.print(panel_group)
|
135
|
-
|
136
|
-
def create_panel(self, content, title, border_style="blue"):
|
137
|
-
return Panel(
|
138
|
-
content,
|
139
|
-
title=title,
|
140
|
-
title_align="left",
|
141
|
-
border_style=border_style,
|
142
|
-
box=HEAVY,
|
143
|
-
expand=True, # Full terminal width
|
144
|
-
padding=(1, 1), # Internal padding
|
145
|
-
)
|
@@ -0,0 +1,169 @@
|
|
1
|
+
from pocketflow import Node, Flow
|
2
|
+
from agentic_blocks.utils.tools_utils import (
|
3
|
+
create_tool_registry,
|
4
|
+
execute_pending_tool_calls,
|
5
|
+
)
|
6
|
+
from agentic_blocks import call_llm, Messages
|
7
|
+
|
8
|
+
|
9
|
+
from rich.console import Group, Console
|
10
|
+
from rich.json import JSON
|
11
|
+
from rich.live import Live
|
12
|
+
from rich.markdown import Markdown
|
13
|
+
from rich.status import Status
|
14
|
+
from rich.text import Text
|
15
|
+
from rich.box import HEAVY
|
16
|
+
from rich.panel import Panel
|
17
|
+
from agentic_blocks.utils.rich_logger import print_response
|
18
|
+
|
19
|
+
|
20
|
+
class Agent:
|
21
|
+
def __init__(self, system_prompt: str, tools: list):
|
22
|
+
self.system_prompt = system_prompt
|
23
|
+
self.tools = tools
|
24
|
+
self.tool_registry = create_tool_registry(tools)
|
25
|
+
self.panels = []
|
26
|
+
|
27
|
+
# Create nodes
|
28
|
+
self.llm_node = self._create_llm_node()
|
29
|
+
self.tool_node = self._create_tool_node()
|
30
|
+
self.answer_node = self._create_answer_node()
|
31
|
+
|
32
|
+
# Set up flow
|
33
|
+
self.llm_node - "tool_node" >> self.tool_node
|
34
|
+
self.tool_node - "llm_node" >> self.llm_node
|
35
|
+
self.llm_node - "answer_node" >> self.answer_node
|
36
|
+
|
37
|
+
self.flow = Flow(self.llm_node)
|
38
|
+
|
39
|
+
def _create_llm_node(self):
|
40
|
+
class LLMNode(Node):
|
41
|
+
def __init__(self, system_prompt, tools):
|
42
|
+
super().__init__()
|
43
|
+
self.system_prompt = system_prompt
|
44
|
+
self.tools = tools
|
45
|
+
|
46
|
+
def prep(self, shared):
|
47
|
+
messages = shared["messages"]
|
48
|
+
return messages
|
49
|
+
|
50
|
+
def exec(self, messages) -> Messages:
|
51
|
+
response = call_llm(messages=messages, tools=self.tools)
|
52
|
+
messages.add_response_message(response)
|
53
|
+
return messages
|
54
|
+
|
55
|
+
def post(self, shared, prep_res, messages):
|
56
|
+
if messages.has_pending_tool_calls():
|
57
|
+
return "tool_node"
|
58
|
+
else:
|
59
|
+
return "answer_node"
|
60
|
+
|
61
|
+
return LLMNode(self.system_prompt, self.tools)
|
62
|
+
|
63
|
+
def _create_tool_node(self):
|
64
|
+
class ToolNode(Node):
|
65
|
+
def __init__(self, tool_registry, agent):
|
66
|
+
super().__init__()
|
67
|
+
self.tool_registry = tool_registry
|
68
|
+
self.agent = agent
|
69
|
+
|
70
|
+
def prep(self, shared):
|
71
|
+
return shared["messages"]
|
72
|
+
|
73
|
+
def exec(self, messages) -> Messages:
|
74
|
+
tool_calls = messages.get_pending_tool_calls()[0]
|
75
|
+
tool_name = tool_calls["tool_name"]
|
76
|
+
tool_arguments = tool_calls["arguments"]
|
77
|
+
|
78
|
+
# Format arguments nicely
|
79
|
+
if isinstance(tool_arguments, dict):
|
80
|
+
args_str = ", ".join(
|
81
|
+
[f"{k}={v}" for k, v in tool_arguments.items()]
|
82
|
+
)
|
83
|
+
formatted_call = f"{tool_name}({args_str})"
|
84
|
+
else:
|
85
|
+
formatted_call = f"{tool_name}({tool_arguments})"
|
86
|
+
|
87
|
+
tool_panel = self.agent.create_panel(formatted_call, "Tool Calls")
|
88
|
+
self.agent.panels.append(tool_panel)
|
89
|
+
|
90
|
+
self.agent.live_log.update(Group(*self.agent.panels))
|
91
|
+
self.agent.live_log.refresh()
|
92
|
+
|
93
|
+
tool_responses = execute_pending_tool_calls(
|
94
|
+
messages, self.tool_registry
|
95
|
+
)
|
96
|
+
messages.add_tool_responses(tool_responses)
|
97
|
+
return messages
|
98
|
+
|
99
|
+
def post(self, shared, prep_res, messages):
|
100
|
+
return "llm_node"
|
101
|
+
|
102
|
+
return ToolNode(self.tool_registry, self)
|
103
|
+
|
104
|
+
def _create_answer_node(self):
|
105
|
+
class AnswerNode(Node):
|
106
|
+
def prep(self, shared):
|
107
|
+
messages = shared["messages"]
|
108
|
+
shared["answer"] = messages.get_messages()[-1]["content"]
|
109
|
+
return messages
|
110
|
+
|
111
|
+
return AnswerNode()
|
112
|
+
|
113
|
+
def invoke(self, user_prompt: str) -> str:
|
114
|
+
messages = Messages(user_prompt=user_prompt)
|
115
|
+
if self.system_prompt:
|
116
|
+
messages.add_system_message(self.system_prompt)
|
117
|
+
|
118
|
+
shared = {"messages": messages}
|
119
|
+
self.flow.run(shared)
|
120
|
+
|
121
|
+
return shared["answer"]
|
122
|
+
|
123
|
+
def create_panel(self, content, title, border_style="blue"):
|
124
|
+
return Panel(
|
125
|
+
content,
|
126
|
+
title=title,
|
127
|
+
title_align="left",
|
128
|
+
border_style=border_style,
|
129
|
+
box=HEAVY,
|
130
|
+
expand=True,
|
131
|
+
padding=(1, 1),
|
132
|
+
)
|
133
|
+
|
134
|
+
def print_response(self, user_prompt: str):
|
135
|
+
messages = Messages(user_prompt=user_prompt)
|
136
|
+
if self.system_prompt:
|
137
|
+
messages.add_system_message(self.system_prompt)
|
138
|
+
|
139
|
+
shared = {"messages": messages}
|
140
|
+
|
141
|
+
with Live(console=Console(), auto_refresh=False) as self.live_log:
|
142
|
+
status = Status("Thinking...", spinner="aesthetic", speed=0.4)
|
143
|
+
self.live_log.update(status)
|
144
|
+
self.live_log.refresh() # Explicit refresh for Jupyter
|
145
|
+
|
146
|
+
self.panels = [status]
|
147
|
+
|
148
|
+
message_panel = self.create_panel(
|
149
|
+
content=Text(user_prompt, style="green"),
|
150
|
+
title="Message",
|
151
|
+
border_style="cyan",
|
152
|
+
)
|
153
|
+
|
154
|
+
self.panels.append(message_panel)
|
155
|
+
self.live_log.update(Group(*self.panels))
|
156
|
+
self.live_log.refresh()
|
157
|
+
|
158
|
+
self.flow.run(shared)
|
159
|
+
response = shared["answer"]
|
160
|
+
|
161
|
+
response_panel = self.create_panel(
|
162
|
+
content=Text(response, style="bold blue"),
|
163
|
+
title="Response",
|
164
|
+
border_style="green",
|
165
|
+
)
|
166
|
+
|
167
|
+
self.panels.append(response_panel)
|
168
|
+
self.live_log.update(Group(*self.panels))
|
169
|
+
self.live_log.refresh()
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import logging
|
2
|
+
|
3
|
+
# Auto-configure logging when module is imported
|
4
|
+
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
|
5
|
+
|
6
|
+
# Suppress HTTP request logs
|
7
|
+
logging.getLogger("openai").setLevel(logging.WARNING)
|
8
|
+
logging.getLogger("httpx").setLevel(logging.WARNING)
|
9
|
+
logging.getLogger("urllib3").setLevel(logging.WARNING)
|
10
|
+
|
11
|
+
|
12
|
+
def get_logger(name):
|
13
|
+
"""Get a logger with the given name."""
|
14
|
+
return logging.getLogger(name)
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import time
|
2
|
+
from rich.console import Group, Console
|
3
|
+
from rich.json import JSON
|
4
|
+
from rich.live import Live
|
5
|
+
from rich.markdown import Markdown
|
6
|
+
from rich.status import Status
|
7
|
+
from rich.text import Text
|
8
|
+
from rich.box import HEAVY
|
9
|
+
from rich.panel import Panel
|
10
|
+
|
11
|
+
# Create a console instance for Jupyter
|
12
|
+
|
13
|
+
|
14
|
+
def create_panel(content, title, border_style="blue"):
|
15
|
+
return Panel(
|
16
|
+
content,
|
17
|
+
title=title,
|
18
|
+
title_align="left",
|
19
|
+
border_style=border_style,
|
20
|
+
box=HEAVY,
|
21
|
+
expand=True,
|
22
|
+
padding=(1, 1),
|
23
|
+
)
|
24
|
+
|
25
|
+
|
26
|
+
def print_response(user_prompt):
|
27
|
+
with Live(console=Console(), auto_refresh=False) as live_log:
|
28
|
+
status = Status("Thinking...", spinner="aesthetic", speed=0.4)
|
29
|
+
live_log.update(status)
|
30
|
+
live_log.refresh() # Explicit refresh for Jupyter
|
31
|
+
|
32
|
+
# Create panels
|
33
|
+
panels = [status]
|
34
|
+
|
35
|
+
message_panel = create_panel(
|
36
|
+
content=Text(user_prompt, style="green"),
|
37
|
+
title="Message",
|
38
|
+
border_style="cyan",
|
39
|
+
)
|
40
|
+
|
41
|
+
panels.append(message_panel)
|
42
|
+
live_log.update(Group(*panels))
|
43
|
+
live_log.refresh() # Explicit refresh for Jupyter
|
44
|
+
|
45
|
+
# Add some delay to see the display
|
46
|
+
|
47
|
+
for i in range(3):
|
48
|
+
time.sleep(2)
|
49
|
+
|
50
|
+
# Add a response panel
|
51
|
+
response_panel = create_panel(
|
52
|
+
content=Text("Response: " + str(i), style="bold blue"),
|
53
|
+
title="Response",
|
54
|
+
border_style="green",
|
55
|
+
)
|
56
|
+
|
57
|
+
panels.append(response_panel)
|
58
|
+
live_log.update(Group(*panels))
|
59
|
+
live_log.refresh()
|
@@ -0,0 +1,15 @@
|
|
1
|
+
agentic_blocks/__init__.py,sha256=LJy2tzTwX9ZjPw8dqkXOWiude7ZDDIaBIvaLC8U4d_Y,435
|
2
|
+
agentic_blocks/agent.py,sha256=gGSHHmPl3p_LguKKxUNhbCZXJV_V6MccmtfoEAC5fO4,3558
|
3
|
+
agentic_blocks/agent_rich.py,sha256=MTMFJ1gEMd3mfj65YxSwh50yp19KZKrP40cRiJfDMdU,5639
|
4
|
+
agentic_blocks/llm.py,sha256=9OnpOFqZ7CoOoy8DECW7gxSGtpw-76hX-NvV003TKBU,5330
|
5
|
+
agentic_blocks/mcp_client.py,sha256=15mIN_Qw0OVNJAvfgO3jVZS4-AU4TtvEQSFDlL9ruqA,9773
|
6
|
+
agentic_blocks/messages.py,sha256=iJEULGGFGHVp8ViE2oKykU9JVfvGKoySCDhxlHm29Lk,12014
|
7
|
+
agentic_blocks/utils/logger.py,sha256=BblwT4Oj6YdHEYV4KtIzpKrcCiRvp_VVC1quk6GN3wo,436
|
8
|
+
agentic_blocks/utils/rich_logger.py,sha256=TT2D9v6bLYGPMiwUvb3mMcGHeCmlvD89dSwCxwDGfMA,1612
|
9
|
+
agentic_blocks/utils/tools_utils.py,sha256=ZX6cqvtaV_evwMUnR_uukdvEtQah6xkDMBy7jwR7tJg,7145
|
10
|
+
agentic_blocks/visualization/visualize.py,sha256=x59lFDKXqaFlereCEhN7GWDimiNRNcb9USeRPv8YY5I,39647
|
11
|
+
agentic_blocks-0.1.25.dist-info/licenses/LICENSE,sha256=r4IcBaAjTv3-yfjXgDPuRD953Qci0Y0nQn5JfHwLyBY,1073
|
12
|
+
agentic_blocks-0.1.25.dist-info/METADATA,sha256=KQes4V0dczfXrwupfrpMd7ywqN3_XEn_GlcJt_hifco,12126
|
13
|
+
agentic_blocks-0.1.25.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
14
|
+
agentic_blocks-0.1.25.dist-info/top_level.txt,sha256=-1a4RAemqicXLU1rRzw4QHV3KlNeQDNxVs3m2gAT238,15
|
15
|
+
agentic_blocks-0.1.25.dist-info/RECORD,,
|
@@ -1,12 +0,0 @@
|
|
1
|
-
agentic_blocks/__init__.py,sha256=LJy2tzTwX9ZjPw8dqkXOWiude7ZDDIaBIvaLC8U4d_Y,435
|
2
|
-
agentic_blocks/agent.py,sha256=KZ2dQnb4IxMK9xOMXFYIBIPofVtLmpISftn-YbSul14,4840
|
3
|
-
agentic_blocks/llm.py,sha256=9OnpOFqZ7CoOoy8DECW7gxSGtpw-76hX-NvV003TKBU,5330
|
4
|
-
agentic_blocks/mcp_client.py,sha256=15mIN_Qw0OVNJAvfgO3jVZS4-AU4TtvEQSFDlL9ruqA,9773
|
5
|
-
agentic_blocks/messages.py,sha256=iJEULGGFGHVp8ViE2oKykU9JVfvGKoySCDhxlHm29Lk,12014
|
6
|
-
agentic_blocks/utils/tools_utils.py,sha256=ZX6cqvtaV_evwMUnR_uukdvEtQah6xkDMBy7jwR7tJg,7145
|
7
|
-
agentic_blocks/visualization/visualize.py,sha256=x59lFDKXqaFlereCEhN7GWDimiNRNcb9USeRPv8YY5I,39647
|
8
|
-
agentic_blocks-0.1.24.dist-info/licenses/LICENSE,sha256=r4IcBaAjTv3-yfjXgDPuRD953Qci0Y0nQn5JfHwLyBY,1073
|
9
|
-
agentic_blocks-0.1.24.dist-info/METADATA,sha256=lNOys5YTca4ZPZmVQ2SBLYKvpBpsfSgKE3y1_5XjjG8,12126
|
10
|
-
agentic_blocks-0.1.24.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
11
|
-
agentic_blocks-0.1.24.dist-info/top_level.txt,sha256=-1a4RAemqicXLU1rRzw4QHV3KlNeQDNxVs3m2gAT238,15
|
12
|
-
agentic_blocks-0.1.24.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|