agentic-blocks 0.1.3__py3-none-any.whl → 0.1.5__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/llm.py +20 -8
- agentic_blocks/mcp_client.py +19 -0
- {agentic_blocks-0.1.3.dist-info → agentic_blocks-0.1.5.dist-info}/METADATA +1 -1
- agentic_blocks-0.1.5.dist-info/RECORD +9 -0
- agentic_blocks-0.1.3.dist-info/RECORD +0 -9
- {agentic_blocks-0.1.3.dist-info → agentic_blocks-0.1.5.dist-info}/WHEEL +0 -0
- {agentic_blocks-0.1.3.dist-info → agentic_blocks-0.1.5.dist-info}/licenses/LICENSE +0 -0
- {agentic_blocks-0.1.3.dist-info → agentic_blocks-0.1.5.dist-info}/top_level.txt +0 -0
agentic_blocks/llm.py
CHANGED
@@ -22,8 +22,9 @@ def call_llm(
|
|
22
22
|
tools: Optional[List[Dict[str, Any]]] = None,
|
23
23
|
api_key: Optional[str] = None,
|
24
24
|
model: str = "gpt-4o-mini",
|
25
|
+
base_url: Optional[str] = None,
|
25
26
|
**kwargs,
|
26
|
-
) ->
|
27
|
+
) -> Any:
|
27
28
|
"""
|
28
29
|
Call an LLM completion API with the provided messages.
|
29
30
|
|
@@ -32,10 +33,11 @@ def call_llm(
|
|
32
33
|
tools: Optional list of tools in OpenAI function calling format
|
33
34
|
api_key: OpenAI API key (if not provided, loads from .env OPENAI_API_KEY)
|
34
35
|
model: Model name to use for completion
|
36
|
+
base_url: Base URL for the API (useful for VLLM or other OpenAI-compatible servers)
|
35
37
|
**kwargs: Additional parameters to pass to OpenAI API
|
36
38
|
|
37
39
|
Returns:
|
38
|
-
The
|
40
|
+
The complete message object from the OpenAI API response
|
39
41
|
|
40
42
|
Raises:
|
41
43
|
LLMError: If API call fails or configuration is invalid
|
@@ -47,13 +49,18 @@ def call_llm(
|
|
47
49
|
if not api_key:
|
48
50
|
api_key = os.getenv("OPENAI_API_KEY")
|
49
51
|
|
50
|
-
if not api_key:
|
52
|
+
if not api_key and not base_url:
|
51
53
|
raise LLMError(
|
52
54
|
"OpenAI API key not found. Set OPENAI_API_KEY environment variable or pass api_key parameter."
|
53
55
|
)
|
54
56
|
|
55
57
|
# Initialize OpenAI client
|
56
|
-
|
58
|
+
client_kwargs = {}
|
59
|
+
if api_key:
|
60
|
+
client_kwargs["api_key"] = api_key
|
61
|
+
if base_url:
|
62
|
+
client_kwargs["base_url"] = base_url
|
63
|
+
client = OpenAI(**client_kwargs)
|
57
64
|
|
58
65
|
# Handle different message input types
|
59
66
|
if isinstance(messages, Messages):
|
@@ -79,8 +86,8 @@ def call_llm(
|
|
79
86
|
# Make completion request
|
80
87
|
response = client.chat.completions.create(**completion_params)
|
81
88
|
|
82
|
-
#
|
83
|
-
return response.choices[0].message
|
89
|
+
# Return the complete message object
|
90
|
+
return response.choices[0].message
|
84
91
|
|
85
92
|
except Exception as e:
|
86
93
|
raise LLMError(f"Failed to call LLM API: {e}")
|
@@ -125,12 +132,17 @@ def example_usage():
|
|
125
132
|
# Call with Messages object
|
126
133
|
print("Using Messages object:")
|
127
134
|
response1 = call_llm(messages_obj, temperature=0.7)
|
128
|
-
print(f"Response: {response1}")
|
135
|
+
print(f"Response: {response1.content}")
|
129
136
|
|
130
137
|
# Call with raw message list
|
131
138
|
print("\nUsing raw message list:")
|
132
139
|
response2 = call_llm(messages_list, tools=tools, temperature=0.5)
|
133
|
-
|
140
|
+
if hasattr(response2, 'tool_calls') and response2.tool_calls:
|
141
|
+
print(f"Tool calls requested: {len(response2.tool_calls)}")
|
142
|
+
for i, tool_call in enumerate(response2.tool_calls):
|
143
|
+
print(f" {i+1}. {tool_call.function.name}({tool_call.function.arguments})")
|
144
|
+
else:
|
145
|
+
print(f"Response: {response2.content}")
|
134
146
|
|
135
147
|
except LLMError as e:
|
136
148
|
print(f"Error: {e}")
|
agentic_blocks/mcp_client.py
CHANGED
@@ -16,6 +16,23 @@ from mcp.client.streamable_http import streamablehttp_client
|
|
16
16
|
logger = logging.getLogger(__name__)
|
17
17
|
|
18
18
|
|
19
|
+
def handle_jupyter_env():
|
20
|
+
"""Apply nest_asyncio if running in a Jupyter notebook environment."""
|
21
|
+
try:
|
22
|
+
# Check if we're in a running event loop (like Jupyter)
|
23
|
+
asyncio.get_running_loop()
|
24
|
+
try:
|
25
|
+
import nest_asyncio
|
26
|
+
nest_asyncio.apply()
|
27
|
+
except ImportError:
|
28
|
+
logger.warning(
|
29
|
+
"nest_asyncio not available. Install with: pip install nest-asyncio"
|
30
|
+
)
|
31
|
+
except RuntimeError:
|
32
|
+
# No event loop running, no need for nest_asyncio
|
33
|
+
pass
|
34
|
+
|
35
|
+
|
19
36
|
class MCPEndpointError(Exception):
|
20
37
|
"""Exception raised when there's an error connecting to or using an MCP endpoint."""
|
21
38
|
|
@@ -77,6 +94,7 @@ class MCPClient:
|
|
77
94
|
Raises:
|
78
95
|
MCPEndpointError: If connection or listing fails
|
79
96
|
"""
|
97
|
+
handle_jupyter_env()
|
80
98
|
return asyncio.run(self.list_tools_async())
|
81
99
|
|
82
100
|
async def list_tools_async(self) -> List[Dict[str, Any]]:
|
@@ -158,6 +176,7 @@ class MCPClient:
|
|
158
176
|
Raises:
|
159
177
|
MCPEndpointError: If connection or tool call fails
|
160
178
|
"""
|
179
|
+
handle_jupyter_env()
|
161
180
|
return asyncio.run(self.call_tool_async(tool_name, arguments))
|
162
181
|
|
163
182
|
async def call_tool_async(
|
@@ -0,0 +1,9 @@
|
|
1
|
+
agentic_blocks/__init__.py,sha256=LJy2tzTwX9ZjPw8dqkXOWiude7ZDDIaBIvaLC8U4d_Y,435
|
2
|
+
agentic_blocks/llm.py,sha256=EetJFAUMAvRYFExjZrVCyeewhqhtnE7o3PvlW9NgKHw,4584
|
3
|
+
agentic_blocks/mcp_client.py,sha256=15mIN_Qw0OVNJAvfgO3jVZS4-AU4TtvEQSFDlL9ruqA,9773
|
4
|
+
agentic_blocks/messages.py,sha256=rwcb_goGwfPiDIzl6Up46pAl-5Kw5aFb0uqd6pQtJPY,8162
|
5
|
+
agentic_blocks-0.1.5.dist-info/licenses/LICENSE,sha256=r4IcBaAjTv3-yfjXgDPuRD953Qci0Y0nQn5JfHwLyBY,1073
|
6
|
+
agentic_blocks-0.1.5.dist-info/METADATA,sha256=zHSVjhDqcM2pnKhX_r_0x6iRNqbBHt-Xc-G2hI4PTx8,9445
|
7
|
+
agentic_blocks-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
8
|
+
agentic_blocks-0.1.5.dist-info/top_level.txt,sha256=-1a4RAemqicXLU1rRzw4QHV3KlNeQDNxVs3m2gAT238,15
|
9
|
+
agentic_blocks-0.1.5.dist-info/RECORD,,
|
@@ -1,9 +0,0 @@
|
|
1
|
-
agentic_blocks/__init__.py,sha256=LJy2tzTwX9ZjPw8dqkXOWiude7ZDDIaBIvaLC8U4d_Y,435
|
2
|
-
agentic_blocks/llm.py,sha256=Rbh0rYDeVyo3S7hRG6tiIfALjchd64zTNz3Q465LUZs,3964
|
3
|
-
agentic_blocks/mcp_client.py,sha256=WsEdgzXw8bM76iJWD5BzoJF7MK9wXcUUd5T0TUAWusw,9175
|
4
|
-
agentic_blocks/messages.py,sha256=rwcb_goGwfPiDIzl6Up46pAl-5Kw5aFb0uqd6pQtJPY,8162
|
5
|
-
agentic_blocks-0.1.3.dist-info/licenses/LICENSE,sha256=r4IcBaAjTv3-yfjXgDPuRD953Qci0Y0nQn5JfHwLyBY,1073
|
6
|
-
agentic_blocks-0.1.3.dist-info/METADATA,sha256=Vyggnjbzq4el1dJP82dUjTKeTj1A8Ap-HXZvUlDNVs4,9445
|
7
|
-
agentic_blocks-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
8
|
-
agentic_blocks-0.1.3.dist-info/top_level.txt,sha256=-1a4RAemqicXLU1rRzw4QHV3KlNeQDNxVs3m2gAT238,15
|
9
|
-
agentic_blocks-0.1.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|