feat: added purchase stock component
This commit is contained in:
@@ -6,7 +6,7 @@ import { z } from "zod";
|
||||
import { LangGraphRunnableConfig } from "@langchain/langgraph";
|
||||
import { findToolCall } from "../../find-tool-call";
|
||||
import { format, subDays } from "date-fns";
|
||||
import { Price } from "../../types";
|
||||
import { Price, Snapshot } from "../../types";
|
||||
|
||||
async function getPricesForTicker(ticker: string): Promise<{
|
||||
oneDayPrices: Price[];
|
||||
@@ -48,21 +48,44 @@ async function getPricesForTicker(ticker: string): Promise<{
|
||||
fetch(`${url}?${queryParamsOneDay.toString()}`, options),
|
||||
fetch(`${url}?${queryParamsThirtyDays.toString()}`, options),
|
||||
]);
|
||||
|
||||
if (!resOneDay.ok || !resThirtyDays.ok) {
|
||||
throw new Error("Failed to fetch prices");
|
||||
}
|
||||
|
||||
const { prices: pricesOneDay } = await resOneDay.json();
|
||||
const { prices: pricesThirtyDays } = await resThirtyDays.json();
|
||||
|
||||
console.log("pricesOneDay", pricesOneDay.length);
|
||||
console.log("pricesThirtyDays", pricesThirtyDays.length);
|
||||
|
||||
return {
|
||||
oneDayPrices: pricesOneDay,
|
||||
thirtyDayPrices: pricesThirtyDays,
|
||||
};
|
||||
}
|
||||
|
||||
async function getPriceSnapshotForTicker(ticker: string): Promise<Snapshot> {
|
||||
if (!process.env.FINANCIAL_DATASETS_API_KEY) {
|
||||
throw new Error("Financial datasets API key not set");
|
||||
}
|
||||
|
||||
const options = {
|
||||
method: "GET",
|
||||
headers: { "X-API-KEY": process.env.FINANCIAL_DATASETS_API_KEY },
|
||||
};
|
||||
const url = "https://api.financialdatasets.ai/prices/snapshot";
|
||||
|
||||
const queryParams = new URLSearchParams({
|
||||
ticker,
|
||||
});
|
||||
|
||||
const response = await fetch(`${url}?${queryParams.toString()}`, options);
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch price snapshot");
|
||||
}
|
||||
|
||||
const { snapshot } = await response.json();
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
const llm = new ChatOpenAI({ model: "gpt-4o-mini", temperature: 0 });
|
||||
|
||||
const getStockPriceSchema = z.object({
|
||||
@@ -71,6 +94,10 @@ const getStockPriceSchema = z.object({
|
||||
const getPortfolioSchema = z.object({
|
||||
get_portfolio: z.boolean().describe("Should be true."),
|
||||
});
|
||||
const buyStockSchema = z.object({
|
||||
ticker: z.string().describe("The ticker symbol of the company"),
|
||||
quantity: z.number().describe("The quantity of the stock to buy"),
|
||||
});
|
||||
|
||||
const STOCKBROKER_TOOLS = [
|
||||
{
|
||||
@@ -84,6 +111,11 @@ const STOCKBROKER_TOOLS = [
|
||||
"A tool to get the user's portfolio details. Only call this tool if the user requests their portfolio details.",
|
||||
schema: getPortfolioSchema,
|
||||
},
|
||||
{
|
||||
name: "buy-stock",
|
||||
description: "A tool to buy a stock",
|
||||
schema: buyStockSchema,
|
||||
},
|
||||
];
|
||||
|
||||
export async function callTools(
|
||||
@@ -107,6 +139,9 @@ export async function callTools(
|
||||
const portfolioToolCall = message.tool_calls?.find(
|
||||
findToolCall("portfolio")<typeof getPortfolioSchema>,
|
||||
);
|
||||
const buyStockToolCall = message.tool_calls?.find(
|
||||
findToolCall("buy-stock")<typeof buyStockSchema>,
|
||||
);
|
||||
|
||||
if (stockbrokerToolCall) {
|
||||
const prices = await getPricesForTicker(stockbrokerToolCall.args.ticker);
|
||||
@@ -115,10 +150,20 @@ export async function callTools(
|
||||
...prices,
|
||||
});
|
||||
}
|
||||
|
||||
if (portfolioToolCall) {
|
||||
ui.write("portfolio", {});
|
||||
}
|
||||
if (buyStockToolCall) {
|
||||
const snapshot = await getPriceSnapshotForTicker(
|
||||
buyStockToolCall.args.ticker,
|
||||
);
|
||||
ui.write("buy-stock", {
|
||||
toolCallId:
|
||||
message.tool_calls?.find((tc) => tc.name === "buy-stock")?.id ?? "",
|
||||
snapshot,
|
||||
quantity: buyStockToolCall.args.quantity,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
messages: [message],
|
||||
|
||||
Reference in New Issue
Block a user