Merge pull request #39 from langchain-ai/dqbd/sdk-js-0.0.52

feat: upgrade to 0.0.52
This commit is contained in:
David Duong
2025-03-10 18:18:29 +01:00
committed by GitHub
8 changed files with 2230 additions and 4347 deletions

View File

@@ -106,17 +106,22 @@ export async function executor(
const fullWriteAccess = !!config.configurable?.permissions?.full_write_access;
const msg = ui.create("proposed-change", {
toolCallId,
change: updateFileContents,
planItem: nextPlanItem,
fullWriteAccess,
});
msg.additional_kwargs["message_id"] = aiMessage.id;
ui.push(
{
name: "proposed-change",
content: {
toolCallId,
change: updateFileContents,
planItem: nextPlanItem,
fullWriteAccess,
},
},
{ message: aiMessage },
);
return {
messages: [aiMessage],
ui: [msg],
ui: ui.items,
timestamp: Date.now(),
};
}

View File

@@ -86,13 +86,18 @@ export async function planner(
],
};
const msg = ui.create("code-plan", {
toolCallId,
executedPlans,
rejectedPlans,
remainingPlans,
});
msg.additional_kwargs["message_id"] = aiMessage.id;
ui.push(
{
name: "code-plan",
content: {
toolCallId,
executedPlans,
rejectedPlans,
remainingPlans,
},
},
{ message: aiMessage },
);
const toolMessage: ToolMessage = {
type: "tool",
@@ -103,7 +108,7 @@ export async function planner(
return {
messages: [aiMessage, toolMessage],
ui: [msg],
ui: ui.items,
timestamp: Date.now(),
};
}

View File

@@ -176,29 +176,38 @@ export async function callTools(
if (stockbrokerToolCall) {
const prices = await getPricesForTicker(stockbrokerToolCall.args.ticker);
ui.write("stock-price", {
ticker: stockbrokerToolCall.args.ticker,
...prices,
});
ui.push(
{
name: "stock-price",
content: { ticker: stockbrokerToolCall.args.ticker, ...prices },
},
{ message },
);
}
if (portfolioToolCall) {
ui.write("portfolio", {});
ui.push({ name: "portfolio", content: {} }, { message });
}
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,
});
ui.push(
{
name: "buy-stock",
content: {
toolCallId:
message.tool_calls?.find((tc) => tc.name === "buy-stock")?.id ?? "",
snapshot,
quantity: buyStockToolCall.args.quantity,
},
},
{ message },
);
}
return {
messages: [message],
ui: ui.collect as StockbrokerUpdate["ui"],
ui: ui.items,
timestamp: Date.now(),
};
}

View File

@@ -87,32 +87,56 @@ export async function callTools(
}
if (tripPlan.listAccommodations) {
ui.write("accommodations-list", {
toolCallId,
...getAccommodationsListProps(state.tripDetails),
});
ui.push(
{
name: "accommodations-list",
content: {
toolCallId,
...getAccommodationsListProps(state.tripDetails),
},
},
{ message: response },
);
}
if (tripPlan.bookAccommodation && tripPlan.accommodationName) {
ui.write("book-accommodation", {
tripDetails: state.tripDetails,
accommodationName: tripPlan.accommodationName,
});
ui.push(
{
name: "book-accommodation",
content: {
tripDetails: state.tripDetails,
accommodationName: tripPlan.accommodationName,
},
},
{ message: response },
);
}
if (tripPlan.listRestaurants) {
ui.write("restaurants-list", { tripDetails: state.tripDetails });
ui.push(
{
name: "restaurants-list",
content: { tripDetails: state.tripDetails },
},
{ message: response },
);
}
if (tripPlan.bookRestaurant && tripPlan.restaurantName) {
ui.write("book-restaurant", {
tripDetails: state.tripDetails,
restaurantName: tripPlan.restaurantName,
});
ui.push(
{
name: "book-restaurant",
content: {
tripDetails: state.tripDetails,
restaurantName: tripPlan.restaurantName,
},
},
{ message: response },
);
}
return {
messages: [response],
ui: ui.collect as TripPlannerUpdate["ui"],
ui: ui.items,
timestamp: Date.now(),
};
}

View File

@@ -22,7 +22,7 @@
"@langchain/langgraph": "^0.2.49",
"@langchain/langgraph-api": "^0.0.14",
"@langchain/langgraph-cli": "^0.0.14",
"@langchain/langgraph-sdk": "^0.0.50",
"@langchain/langgraph-sdk": "^0.0.52",
"@langchain/openai": "^0.4.4",
"@radix-ui/react-avatar": "^1.1.3",
"@radix-ui/react-dialog": "^1.1.6",

6415
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,8 +7,8 @@ import { MarkdownText } from "../markdown-text";
import { LoadExternalComponent } from "@langchain/langgraph-sdk/react-ui";
import { cn } from "@/lib/utils";
import { ToolCalls, ToolResult } from "./tool-calls";
import { StringParam, useQueryParam } from "use-query-params";
import { MessageContentComplex } from "@langchain/core/messages";
import { Fragment } from "react/jsx-runtime";
function CustomComponent({
message,
@@ -17,32 +17,28 @@ function CustomComponent({
message: Message;
thread: ReturnType<typeof useStreamContext>;
}) {
const [apiUrl] = useQueryParam("apiUrl", StringParam);
const meta = thread.getMessagesMetadata(message);
const seenState = meta?.firstSeenState;
const customComponents = seenState?.values.ui
?.slice()
.filter(
({ additional_kwargs }) =>
additional_kwargs.run_id === seenState.metadata?.run_id &&
(!additional_kwargs.message_id ||
additional_kwargs.message_id === message.id),
.filter(({ additional_kwargs }) =>
!additional_kwargs.message_id
? additional_kwargs.run_id === seenState.metadata?.run_id
: additional_kwargs.message_id === message.id,
);
if (!customComponents?.length) return null;
return (
<div key={message.id}>
<Fragment key={message.id}>
{customComponents.map((customComponent) => (
<LoadExternalComponent
key={customComponent.id}
apiUrl={apiUrl ?? undefined}
assistantId="agent"
stream={thread}
message={customComponent}
meta={{ ui: customComponent }}
/>
))}
</div>
</Fragment>
);
}

View File

@@ -1,9 +1,10 @@
import React, { createContext, useContext, ReactNode, useState } from "react";
import { useStream } from "@langchain/langgraph-sdk/react";
import { type Message } from "@langchain/langgraph-sdk";
import type {
UIMessage,
RemoveUIMessage,
import {
uiMessageReducer,
type UIMessage,
type RemoveUIMessage,
} from "@langchain/langgraph-sdk/react-ui";
import { useQueryParam, StringParam } from "use-query-params";
import { Input } from "@/components/ui/input";
@@ -24,7 +25,7 @@ const useTypedStream = useStream<
messages?: Message[] | Message | string;
ui?: (UIMessage | RemoveUIMessage)[] | UIMessage | RemoveUIMessage;
};
CustomUpdateType: UIMessage | RemoveUIMessage;
CustomEventType: UIMessage | RemoveUIMessage;
}
>;
@@ -53,6 +54,12 @@ const StreamSession = ({
apiKey: apiKey ?? undefined,
assistantId,
threadId: threadId ?? null,
onCustomEvent: (event, options) => {
options.mutate((prev) => {
const ui = uiMessageReducer(prev.ui ?? [], event);
return { ...prev, ui };
});
},
onThreadId: (id) => {
setThreadId(id);
// Refetch threads list when thread ID changes.