agentic-blocks 0.1.24__tar.gz → 0.1.25__tar.gz

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.
Files changed (20) hide show
  1. {agentic_blocks-0.1.24/src/agentic_blocks.egg-info → agentic_blocks-0.1.25}/PKG-INFO +1 -1
  2. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/pyproject.toml +1 -1
  3. agentic_blocks-0.1.25/src/agentic_blocks/agent.py +104 -0
  4. agentic_blocks-0.1.24/src/agentic_blocks/agent.py → agentic_blocks-0.1.25/src/agentic_blocks/agent_rich.py +52 -28
  5. agentic_blocks-0.1.25/src/agentic_blocks/utils/logger.py +14 -0
  6. agentic_blocks-0.1.25/src/agentic_blocks/utils/rich_logger.py +59 -0
  7. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25/src/agentic_blocks.egg-info}/PKG-INFO +1 -1
  8. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/src/agentic_blocks.egg-info/SOURCES.txt +3 -0
  9. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/LICENSE +0 -0
  10. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/README.md +0 -0
  11. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/setup.cfg +0 -0
  12. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/src/agentic_blocks/__init__.py +0 -0
  13. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/src/agentic_blocks/llm.py +0 -0
  14. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/src/agentic_blocks/mcp_client.py +0 -0
  15. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/src/agentic_blocks/messages.py +0 -0
  16. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/src/agentic_blocks/utils/tools_utils.py +0 -0
  17. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/src/agentic_blocks/visualization/visualize.py +0 -0
  18. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/src/agentic_blocks.egg-info/dependency_links.txt +0 -0
  19. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/src/agentic_blocks.egg-info/requires.txt +0 -0
  20. {agentic_blocks-0.1.24 → agentic_blocks-0.1.25}/src/agentic_blocks.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentic-blocks
3
- Version: 0.1.24
3
+ Version: 0.1.25
4
4
  Summary: Simple building blocks for agentic AI systems with MCP client and conversation management
5
5
  Author-email: Magnus Bjelkenhed <bjelkenhed@gmail.com>
6
6
  License: MIT
@@ -14,7 +14,7 @@ agentic_blocks = []
14
14
 
15
15
  [project]
16
16
  name = "agentic-blocks"
17
- version = "0.1.24"
17
+ version = "0.1.25"
18
18
  description = "Simple building blocks for agentic AI systems with MCP client and conversation management"
19
19
  readme = "README.md"
20
20
  requires-python = ">=3.11"
@@ -0,0 +1,104 @@
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.utils.logger import get_logger
7
+ from agentic_blocks import call_llm, Messages
8
+
9
+ logger = get_logger(__name__)
10
+
11
+
12
+ class Agent:
13
+ def __init__(self, system_prompt: str, tools: list):
14
+ self.system_prompt = system_prompt
15
+ self.tools = tools
16
+ self.tool_registry = create_tool_registry(tools)
17
+
18
+ # Create nodes
19
+ self.llm_node = self._create_llm_node()
20
+ self.tool_node = self._create_tool_node()
21
+ self.answer_node = self._create_answer_node()
22
+
23
+ # Set up flow
24
+ self.llm_node - "tool_node" >> self.tool_node
25
+ self.tool_node - "llm_node" >> self.llm_node
26
+ self.llm_node - "answer_node" >> self.answer_node
27
+
28
+ self.flow = Flow(self.llm_node)
29
+
30
+ def _create_llm_node(self):
31
+ class LLMNode(Node):
32
+ def __init__(self, system_prompt, tools):
33
+ super().__init__()
34
+ self.system_prompt = system_prompt
35
+ self.tools = tools
36
+
37
+ def prep(self, shared):
38
+ messages = shared["messages"]
39
+ return messages
40
+
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
+
46
+ response = call_llm(messages=messages, tools=self.tools)
47
+ # logger.info(f'response: "{response["content"] or "tool_calls"}"')
48
+ messages.add_response_message(response)
49
+ return messages
50
+
51
+ def post(self, shared, prep_res, messages):
52
+ if messages.has_pending_tool_calls():
53
+ return "tool_node"
54
+ else:
55
+ return "answer_node"
56
+
57
+ return LLMNode(self.system_prompt, self.tools)
58
+
59
+ def _create_tool_node(self):
60
+ class ToolNode(Node):
61
+ def __init__(self, tool_registry):
62
+ super().__init__()
63
+ self.tool_registry = tool_registry
64
+
65
+ def prep(self, shared):
66
+ return shared["messages"]
67
+
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"]})"'
73
+ )
74
+
75
+ tool_responses = execute_pending_tool_calls(
76
+ messages, self.tool_registry
77
+ )
78
+ messages.add_tool_responses(tool_responses)
79
+ return messages
80
+
81
+ def post(self, shared, prep_res, messages):
82
+ return "llm_node"
83
+
84
+ return ToolNode(self.tool_registry)
85
+
86
+ def _create_answer_node(self):
87
+ class AnswerNode(Node):
88
+ def prep(self, shared):
89
+ messages = shared["messages"]
90
+ shared["answer"] = messages.get_messages()[-1]["content"]
91
+ return messages
92
+
93
+ return AnswerNode()
94
+
95
+ def invoke(self, user_prompt: str) -> str:
96
+ messages = Messages(user_prompt=user_prompt)
97
+ logger.info(f'message: "{user_prompt}"')
98
+ if self.system_prompt:
99
+ messages.add_system_message(self.system_prompt)
100
+
101
+ shared = {"messages": messages}
102
+ self.flow.run(shared)
103
+
104
+ return shared["answer"]
@@ -4,18 +4,17 @@ from agentic_blocks.utils.tools_utils import (
4
4
  execute_pending_tool_calls,
5
5
  )
6
6
  from agentic_blocks import call_llm, Messages
7
- from rich.panel import Panel
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
8
15
  from rich.box import HEAVY
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
- )
16
+ from rich.panel import Panel
17
+ from agentic_blocks.utils.rich_logger import print_response
19
18
 
20
19
 
21
20
  class Agent:
@@ -88,6 +87,9 @@ class Agent:
88
87
  tool_panel = self.agent.create_panel(formatted_call, "Tool Calls")
89
88
  self.agent.panels.append(tool_panel)
90
89
 
90
+ self.agent.live_log.update(Group(*self.agent.panels))
91
+ self.agent.live_log.refresh()
92
+
91
93
  tool_responses = execute_pending_tool_calls(
92
94
  messages, self.tool_registry
93
95
  )
@@ -118,21 +120,6 @@ class Agent:
118
120
 
119
121
  return shared["answer"]
120
122
 
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
123
  def create_panel(self, content, title, border_style="blue"):
137
124
  return Panel(
138
125
  content,
@@ -140,6 +127,43 @@ class Agent:
140
127
  title_align="left",
141
128
  border_style=border_style,
142
129
  box=HEAVY,
143
- expand=True, # Full terminal width
144
- padding=(1, 1), # Internal padding
130
+ expand=True,
131
+ padding=(1, 1),
145
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()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentic-blocks
3
- Version: 0.1.24
3
+ Version: 0.1.25
4
4
  Summary: Simple building blocks for agentic AI systems with MCP client and conversation management
5
5
  Author-email: Magnus Bjelkenhed <bjelkenhed@gmail.com>
6
6
  License: MIT
@@ -3,6 +3,7 @@ README.md
3
3
  pyproject.toml
4
4
  src/agentic_blocks/__init__.py
5
5
  src/agentic_blocks/agent.py
6
+ src/agentic_blocks/agent_rich.py
6
7
  src/agentic_blocks/llm.py
7
8
  src/agentic_blocks/mcp_client.py
8
9
  src/agentic_blocks/messages.py
@@ -11,5 +12,7 @@ src/agentic_blocks.egg-info/SOURCES.txt
11
12
  src/agentic_blocks.egg-info/dependency_links.txt
12
13
  src/agentic_blocks.egg-info/requires.txt
13
14
  src/agentic_blocks.egg-info/top_level.txt
15
+ src/agentic_blocks/utils/logger.py
16
+ src/agentic_blocks/utils/rich_logger.py
14
17
  src/agentic_blocks/utils/tools_utils.py
15
18
  src/agentic_blocks/visualization/visualize.py
File without changes