prompt-caller 0.1.4__py3-none-any.whl → 0.2.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.
@@ -1,12 +1,16 @@
1
1
  import os
2
2
  import re
3
+ import ast
3
4
 
4
5
  import requests
5
6
  import yaml
6
7
  from dotenv import load_dotenv
7
8
  from jinja2 import Template
9
+ from langgraph.types import Command
8
10
  from langchain_core.tools import tool
9
11
  from langchain_core.messages import HumanMessage, SystemMessage, ToolMessage
12
+ from langchain.agents import create_agent
13
+ from langchain.agents.middleware import wrap_tool_call
10
14
  from langchain_openai import ChatOpenAI
11
15
  from langchain_google_genai import ChatGoogleGenerativeAI
12
16
  from PIL import Image
@@ -157,86 +161,88 @@ class PromptCaller:
157
161
 
158
162
  return response
159
163
 
164
+ def _create_media_middleware(self):
165
+ """Middleware to handle tool responses that contain media content (images, PDFs)."""
166
+
167
+ @wrap_tool_call
168
+ def handle_media_response(request, handler):
169
+ result = handler(request)
170
+
171
+ if hasattr(result, "content"):
172
+ content = result.content
173
+
174
+ if isinstance(content, str) and content.startswith("["):
175
+ try:
176
+ content = ast.literal_eval(content)
177
+ except (ValueError, SyntaxError):
178
+ pass
179
+
180
+ # Check if content is media (image or PDF)
181
+ if (
182
+ isinstance(content, list)
183
+ and content
184
+ and isinstance(content[0], dict)
185
+ ):
186
+ is_media = (
187
+ "image_url" in content[0] # Image
188
+ or ("input_file" == content[0].get("type", "").strip()) # PDF
189
+ )
190
+ if is_media:
191
+ return Command(
192
+ update={"messages": [result, HumanMessage(content=content)]}
193
+ )
194
+
195
+ return result
196
+
197
+ return handle_media_response
198
+
160
199
  def agent(
161
200
  self, promptName, context=None, tools=None, output=None, allowed_steps=10
162
201
  ):
163
202
  configuration, messages = self.loadPrompt(promptName, context)
164
203
 
204
+ # Handle structured output from config
165
205
  dynamicOutput = None
166
-
167
206
  if output is None and "output" in configuration:
168
- dynamicOutput = configuration.get("output")
169
- configuration.pop("output")
170
-
171
- for message in messages:
172
- if isinstance(message, SystemMessage):
173
- message.content += "\n\nYou have to use the tool `dynamicmodel` when providing your final answer. If you don't, you have failed the task."
174
- break
207
+ dynamicOutput = configuration.pop("output")
175
208
 
176
209
  chat = self._createChat(configuration)
177
210
 
178
- # Register the tools
211
+ # Prepare tools
179
212
  if tools is None:
180
213
  tools = []
181
-
182
- # Transform functions in tools
183
214
  tools = [tool(t) for t in tools]
184
215
 
185
- tools_dict = {t.name.lower(): t for t in tools}
186
-
216
+ # Handle response format (structured output)
217
+ response_format = None
187
218
  if output:
188
- tools.extend([output])
189
- tools_dict[output.__name__.lower()] = output
219
+ response_format = output
190
220
  elif dynamicOutput:
191
- dynamicModel = self.createPydanticModel(dynamicOutput)
192
-
193
- tools.extend([dynamicModel])
194
- tools_dict["dynamicmodel"] = dynamicModel
195
-
196
- chat = chat.bind_tools(tools)
197
-
198
- try:
199
- # First LLM invocation
200
- response = chat.invoke(messages)
201
- messages.append(response)
202
-
203
- steps = 0
204
- while response.tool_calls and steps < allowed_steps:
205
- for tool_call in response.tool_calls:
206
- tool_name = tool_call["name"].lower()
207
-
208
- # If it's the final formatting tool, validate and return
209
- if dynamicOutput and tool_name == "dynamicmodel":
210
- return dynamicModel.model_validate(tool_call["args"])
211
-
212
- if output and tool_name == output.__name__.lower():
213
- return output.model_validate(tool_call["args"])
214
-
215
- selected_tool = tools_dict.get(tool_name)
216
- if not selected_tool:
217
- raise ValueError(f"Unknown tool: {tool_name}")
218
-
219
- # Invoke the selected tool with provided arguments
220
- tool_response = selected_tool.invoke(tool_call)
221
- messages.append(tool_response)
222
-
223
- # If the latest message is a ToolMessage, re-invoke the LLM
224
- if isinstance(messages[-1], ToolMessage):
225
- response = chat.invoke(messages)
226
- messages.append(response)
227
- else:
228
- break
229
-
230
- steps += 1
231
-
232
- # Final LLM call if the last message is still a ToolMessage
233
- if isinstance(messages[-1], ToolMessage):
234
- response = chat.invoke(messages)
235
- messages.append(response)
221
+ response_format = self.createPydanticModel(dynamicOutput)
222
+
223
+ # Extract system message for create_agent
224
+ system_prompt = None
225
+ user_messages = []
226
+ for msg in messages:
227
+ if isinstance(msg, SystemMessage):
228
+ system_prompt = msg.content
229
+ else:
230
+ user_messages.append(msg)
231
+
232
+ # Create and invoke agent
233
+ agent_graph = create_agent(
234
+ model=chat,
235
+ tools=tools,
236
+ system_prompt=system_prompt,
237
+ response_format=response_format,
238
+ middleware=[self._create_media_middleware()],
239
+ )
236
240
 
237
- return response
241
+ result = agent_graph.invoke(
242
+ {"messages": user_messages}, config={"recursion_limit": allowed_steps}
243
+ )
238
244
 
239
- except Exception as e:
240
- print(e)
241
- # Replace with appropriate logging in production
242
- raise RuntimeError("Error during agent process") from e
245
+ # Return structured output or last message
246
+ if response_format and result.get("structured_response"):
247
+ return result["structured_response"]
248
+ return result["messages"][-1]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prompt_caller
3
- Version: 0.1.4
3
+ Version: 0.2.1
4
4
  Summary: This package is responsible for calling prompts in a specific format. It uses LangChain and OpenAI API
5
5
  Home-page: https://github.com/ThiNepo/prompt-caller
6
6
  Author: Thiago Nepomuceno
@@ -11,12 +11,13 @@ Classifier: Operating System :: OS Independent
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
13
  Requires-Dist: pyyaml>=6.0.2
14
- Requires-Dist: python-dotenv>=1.0.1
14
+ Requires-Dist: python-dotenv>=1.2.1
15
15
  Requires-Dist: Jinja2>=3.1.4
16
- Requires-Dist: langchain-openai>=0.3.5
17
- Requires-Dist: langchain-google-genai==2.1.5
18
- Requires-Dist: openai>=1.63.0
19
- Requires-Dist: pillow>=11.0.0
16
+ Requires-Dist: langchain>=1.2.7
17
+ Requires-Dist: langchain-openai>=1.1.7
18
+ Requires-Dist: langchain-google-genai>=4.2.0
19
+ Requires-Dist: openai>=2.16.0
20
+ Requires-Dist: pillow>=12.1.0
20
21
 
21
22
  # PromptCaller
22
23
 
@@ -0,0 +1,8 @@
1
+ prompt_caller/__init__.py,sha256=4EGdeAJ_Ig7A-b-e17-nYbiXjckT7uL3to5lchMsoW4,41
2
+ prompt_caller/__main__.py,sha256=dJ0dYtVmnhZuoV79R6YiAIta1ZkUKb-TEX4VEuYbgk0,139
3
+ prompt_caller/prompt_caller.py,sha256=U2K_qMMuTBP94cjdac7gPhac8Y6DGOSClfIBFuwpztg,8356
4
+ prompt_caller-0.2.1.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
5
+ prompt_caller-0.2.1.dist-info/METADATA,sha256=b7cSmJA138gThOs1rB298gyS_yFPmbA4OlDfAAEXqL0,4988
6
+ prompt_caller-0.2.1.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
7
+ prompt_caller-0.2.1.dist-info/top_level.txt,sha256=iihiDRq-0VrKB8IKjxf7Lrtv-fLMq4tvgM4fH3x0I94,14
8
+ prompt_caller-0.2.1.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- prompt_caller/__init__.py,sha256=4EGdeAJ_Ig7A-b-e17-nYbiXjckT7uL3to5lchMsoW4,41
2
- prompt_caller/__main__.py,sha256=dJ0dYtVmnhZuoV79R6YiAIta1ZkUKb-TEX4VEuYbgk0,139
3
- prompt_caller/prompt_caller.py,sha256=0Rqfzp7hUgPH10auxEwJMoaASOSZNlTyDvS8Hd6X0Yk,8333
4
- prompt_caller-0.1.4.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
5
- prompt_caller-0.1.4.dist-info/METADATA,sha256=0x0EKp50KvL-dYuc9n8TEvouL53jD_V1fMw2bSKGPEY,4955
6
- prompt_caller-0.1.4.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
7
- prompt_caller-0.1.4.dist-info/top_level.txt,sha256=iihiDRq-0VrKB8IKjxf7Lrtv-fLMq4tvgM4fH3x0I94,14
8
- prompt_caller-0.1.4.dist-info/RECORD,,