Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions ionic_langchain/prompt.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
TOOL_PROMPT = """
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could stand for a broader update this is pretty old. Added a ticket for later: https://linear.app/ionic-commerce/issue/ION-535/update-langchain-prompt

Ionic is an ecommerce shopping tool. Assistant uses the Ionic Commerce Shopping Tool to find, discover, and compare products from thousands of online retailers. Assistant should use the tool when the user is looking for a product recommendation or trying to find a specific product.
Ionic is an ecommerce shopping tool. Assistant uses the Ionic Commerce Shopping Tool to find, discover, and compare products from thousands of online retailers. Assistant should use the tool when the user is looking for a product recommendation or trying to find a specific product.

Ionic Tool input is a stringified List of each search value, for example `['coffee beans']` or `['coffee beans', 'coffee grinder']` and returns results for each search.
The user can specify the number of results, minimum price, and maximum price that they want to see results for.
Ionic Tool input is a comma seperated string of values: query (required), number of results (default to 5), minimum price in cents, and maximum price in cents. For example `coffee beans, 5, 500, 1000` or `coffee beans, 5` or `coffee beans, 5, 500` or `coffee beans, 5, , 1000`. If the user has not specified how many results they want, use 5 as the default.
Convert the price to cents before passing to the tool. For example, if the user asks for a product between $5 and $10, you would pass `500` and `1000` to the tool.

If the human asks for what items are needed for an activity or project, you can provide product recommendations alongside your response about the required items instead of waiting for the user to follow up after.
For example, if the user asks 'what do I need to go camping?', you would compile your list of product requirements for camping (e.g. 'tent', 'stove', 'sleeping bag'), and before responding to user you might use Ionic Tool for
Expand Down
63 changes: 51 additions & 12 deletions ionic_langchain/tool.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from __future__ import annotations

import dataclasses
from typing import Any, Optional
from typing import Any, Optional, Sequence

from ionic import Ionic as IonicSDK
from ionic.models.components import QueryAPIRequest, Query
from ionic.models.operations import QuerySecurity, QueryResponse
from langchain.tools import Tool
from ionic.models.components import Query as SDKQuery, QueryAPIRequest
from ionic.models.operations import QueryResponse, QuerySecurity
from langchain_core.tools import Tool

from ionic_langchain.prompt import TOOL_PROMPT

Expand All @@ -18,20 +20,53 @@ def __init__(self, sdk: Optional[IonicSDK] = None):
else:
self._sdk = IonicSDK()

def query(self, queries: str) -> list:
"""
FIXME: handle non-200 responses
TODO: better typing in response
"""
def query(
self,
query_input: str,
) -> Sequence[dict[str, Any]]:
if not query_input:
raise ValueError("query must not be empty")

query, num_results, min_price, max_price = self.gen_query_request(query_input)
request = QueryAPIRequest(
queries=[Query(query=query) for query in queries.split(", ")],
query=SDKQuery(
query=query,
num_results=num_results,
min_price=min_price,
max_price=max_price,
)
)
response: QueryResponse = self._sdk.query(
request=request,
security=QuerySecurity(),
)

return [dataclasses.asdict(r) for r in response.query_api_response.results]
return [
dataclasses.asdict(result) for result in response.query_api_response.results
]

def _parse_number(self, value: str) -> int | None:
return int(value) if value and int(value) >= 0 else None

def gen_query_request(self, query_input: str) -> tuple[str, int | None, int | None, int | None]:
if not query_input:
raise ValueError("query must not be empty")

split_query = query_input.split(",")
len4_query = split_query + [None] * (4 - len(split_query)) # pad with None

query, num_results, min_price, max_price, *rest = [ # *rest ignores extra values
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How certain are we that the given query_input matches the correct format?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its the format that is specified in the prompt. 😅

item.strip() if item is not None else None for item in len4_query
]
if not query:
raise ValueError("query must not be empty")

return (
str(query),
self._parse_number(num_results),
self._parse_number(min_price),
self._parse_number(max_price),
)


class IonicTool:
Expand All @@ -44,7 +79,11 @@ def __init__(self, ionic: Optional[Ionic] = None):
self._ionic = Ionic()

def tool(self) -> Tool:
return Tool(
"""
- https://github.com/langchain-ai/langchain/issues/4197
- https://python.langchain.com/docs/modules/agents/tools/multi_input_tool
"""
return Tool.from_function(
func=self._ionic.query,
name="Ionic Commerce Shopping Tool",
description=TOOL_PROMPT,
Expand Down
Loading