mirror of
https://github.com/hwchase17/langchain
synced 2024-11-04 06:00:26 +00:00
Add support for HTTP PUT in the open api agent prompt (#10763)
**Description:** This PR adds HTTP PUT support for the langchain openapi agent toolkit by leveraging existing structure and HTTP put request wrapper. The PUT method is almost identical to HTTP POST but should be idempotent and therefore tighter than POST which is not idempotent. Some APIs may consider to use PUT instead of POST which is unfortunately not supported with the current toolkit yet.
This commit is contained in:
parent
a29cd89923
commit
931b292126
@ -19,10 +19,12 @@ from langchain.agents.agent_toolkits.openapi.planner_prompt import (
|
|||||||
PARSING_GET_PROMPT,
|
PARSING_GET_PROMPT,
|
||||||
PARSING_PATCH_PROMPT,
|
PARSING_PATCH_PROMPT,
|
||||||
PARSING_POST_PROMPT,
|
PARSING_POST_PROMPT,
|
||||||
|
PARSING_PUT_PROMPT,
|
||||||
REQUESTS_DELETE_TOOL_DESCRIPTION,
|
REQUESTS_DELETE_TOOL_DESCRIPTION,
|
||||||
REQUESTS_GET_TOOL_DESCRIPTION,
|
REQUESTS_GET_TOOL_DESCRIPTION,
|
||||||
REQUESTS_PATCH_TOOL_DESCRIPTION,
|
REQUESTS_PATCH_TOOL_DESCRIPTION,
|
||||||
REQUESTS_POST_TOOL_DESCRIPTION,
|
REQUESTS_POST_TOOL_DESCRIPTION,
|
||||||
|
REQUESTS_PUT_TOOL_DESCRIPTION,
|
||||||
)
|
)
|
||||||
from langchain.agents.agent_toolkits.openapi.spec import ReducedOpenAPISpec
|
from langchain.agents.agent_toolkits.openapi.spec import ReducedOpenAPISpec
|
||||||
from langchain.agents.mrkl.base import ZeroShotAgent
|
from langchain.agents.mrkl.base import ZeroShotAgent
|
||||||
@ -151,6 +153,35 @@ class RequestsPatchToolWithParsing(BaseRequestsTool, BaseTool):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
class RequestsPutToolWithParsing(BaseRequestsTool, BaseTool):
|
||||||
|
"""Requests PUT tool with LLM-instructed extraction of truncated responses."""
|
||||||
|
|
||||||
|
name: str = "requests_put"
|
||||||
|
"""Tool name."""
|
||||||
|
description = REQUESTS_PUT_TOOL_DESCRIPTION
|
||||||
|
"""Tool description."""
|
||||||
|
response_length: Optional[int] = MAX_RESPONSE_LENGTH
|
||||||
|
"""Maximum length of the response to be returned."""
|
||||||
|
llm_chain: LLMChain = Field(
|
||||||
|
default_factory=_get_default_llm_chain_factory(PARSING_PUT_PROMPT)
|
||||||
|
)
|
||||||
|
"""LLMChain used to extract the response."""
|
||||||
|
|
||||||
|
def _run(self, text: str) -> str:
|
||||||
|
try:
|
||||||
|
data = json.loads(text)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
raise e
|
||||||
|
response = self.requests_wrapper.put(data["url"], data["data"])
|
||||||
|
response = response[: self.response_length]
|
||||||
|
return self.llm_chain.predict(
|
||||||
|
response=response, instructions=data["output_instructions"]
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
async def _arun(self, text: str) -> str:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
class RequestsDeleteToolWithParsing(BaseRequestsTool, BaseTool):
|
class RequestsDeleteToolWithParsing(BaseRequestsTool, BaseTool):
|
||||||
"""A tool that sends a DELETE request and parses the response."""
|
"""A tool that sends a DELETE request and parses the response."""
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ GET /user to get information about the current user
|
|||||||
GET /products/search search across products
|
GET /products/search search across products
|
||||||
POST /users/{{id}}/cart to add products to a user's cart
|
POST /users/{{id}}/cart to add products to a user's cart
|
||||||
PATCH /users/{{id}}/cart to update a user's cart
|
PATCH /users/{{id}}/cart to update a user's cart
|
||||||
|
PUT /users/{{id}}/coupon to apply idempotent coupon to a user's cart
|
||||||
DELETE /users/{{id}}/cart to delete a user's cart
|
DELETE /users/{{id}}/cart to delete a user's cart
|
||||||
|
|
||||||
User query: tell me a joke
|
User query: tell me a joke
|
||||||
@ -39,6 +40,10 @@ Plan: 1. GET /products with a query param to search for lamps
|
|||||||
2. GET /user to find the user's id
|
2. GET /user to find the user's id
|
||||||
3. PATCH /users/{{id}}/cart to add a lamp to the user's cart
|
3. PATCH /users/{{id}}/cart to add a lamp to the user's cart
|
||||||
|
|
||||||
|
User query: I want to add a coupon to my cart
|
||||||
|
Plan: 1. GET /user to find the user's id
|
||||||
|
2. PUT /users/{{id}}/coupon to apply the coupon
|
||||||
|
|
||||||
User query: I want to delete my cart
|
User query: I want to delete my cart
|
||||||
Plan: 1. GET /user to find the user's id
|
Plan: 1. GET /user to find the user's id
|
||||||
2. DELETE required. Did user specify DELETE or previously authorize? Yes, proceed.
|
2. DELETE required. Did user specify DELETE or previously authorize? Yes, proceed.
|
||||||
@ -195,6 +200,23 @@ Output:""",
|
|||||||
input_variables=["response", "instructions"],
|
input_variables=["response", "instructions"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
REQUESTS_PUT_TOOL_DESCRIPTION = """Use this when you want to PUT to a website.
|
||||||
|
Input to the tool should be a json string with 3 keys: "url", "data", and "output_instructions".
|
||||||
|
The value of "url" should be a string.
|
||||||
|
The value of "data" should be a dictionary of key-value pairs you want to PUT to the url.
|
||||||
|
The value of "output_instructions" should be instructions on what information to extract from the response, for example the id(s) for a resource(s) that the PUT request creates.
|
||||||
|
Always use double quotes for strings in the json string."""
|
||||||
|
|
||||||
|
PARSING_PUT_PROMPT = PromptTemplate(
|
||||||
|
template="""Here is an API response:\n\n{response}\n\n====
|
||||||
|
Your task is to extract some information according to these instructions: {instructions}
|
||||||
|
When working with API objects, you should usually use ids over names. Do not return any ids or names that are not in the response.
|
||||||
|
If the response indicates an error, you should instead output a summary of the error.
|
||||||
|
|
||||||
|
Output:""",
|
||||||
|
input_variables=["response", "instructions"],
|
||||||
|
)
|
||||||
|
|
||||||
REQUESTS_DELETE_TOOL_DESCRIPTION = """ONLY USE THIS TOOL WHEN THE USER HAS SPECIFICALLY REQUESTED TO DELETE CONTENT FROM A WEBSITE.
|
REQUESTS_DELETE_TOOL_DESCRIPTION = """ONLY USE THIS TOOL WHEN THE USER HAS SPECIFICALLY REQUESTED TO DELETE CONTENT FROM A WEBSITE.
|
||||||
Input to the tool should be a json string with 2 keys: "url", and "output_instructions".
|
Input to the tool should be a json string with 2 keys: "url", and "output_instructions".
|
||||||
The value of "url" should be a string.
|
The value of "url" should be a string.
|
||||||
|
@ -31,12 +31,12 @@ def reduce_openapi_spec(spec: dict, dereference: bool = True) -> ReducedOpenAPIS
|
|||||||
I was hoping https://openapi.tools/ would have some useful bits
|
I was hoping https://openapi.tools/ would have some useful bits
|
||||||
to this end, but doesn't seem so.
|
to this end, but doesn't seem so.
|
||||||
"""
|
"""
|
||||||
# 1. Consider only get, post, patch, delete endpoints.
|
# 1. Consider only get, post, patch, put, delete endpoints.
|
||||||
endpoints = [
|
endpoints = [
|
||||||
(f"{operation_name.upper()} {route}", docs.get("description"), docs)
|
(f"{operation_name.upper()} {route}", docs.get("description"), docs)
|
||||||
for route, operation in spec["paths"].items()
|
for route, operation in spec["paths"].items()
|
||||||
for operation_name, docs in operation.items()
|
for operation_name, docs in operation.items()
|
||||||
if operation_name in ["get", "post", "patch", "delete"]
|
if operation_name in ["get", "post", "patch", "put", "delete"]
|
||||||
]
|
]
|
||||||
|
|
||||||
# 2. Replace any refs so that complete docs are retrieved.
|
# 2. Replace any refs so that complete docs are retrieved.
|
||||||
|
Loading…
Reference in New Issue
Block a user