Skip to content

Commit

Permalink
core[minor]: Allow for simple tool schema to be passed to bindTools (#…
Browse files Browse the repository at this point in the history
…6253)

* core[minor]: Allow for simple tool schema to be passed to bindTools

* implement in all places where bindTools exists

* chore: lint files

* chore: lint files

* chore: lint files

* renaming refactor

* cr

* BRUH mark gcommon as workspace not latest

* openai[minor],core[minor]: Add support for passing strict in openai tools

* add integration test

* chore: lint files

* Cr

* cr

* fix

* fixed all tests

* docs

* fix build errors

* fix more type errors

* cr

* cr

* chore: lint files

* chore: lint files
  • Loading branch information
bracesproul authored Aug 6, 2024
1 parent 1296334 commit 2edbcda
Show file tree
Hide file tree
Showing 25 changed files with 227 additions and 312 deletions.
20 changes: 13 additions & 7 deletions langchain-core/src/language_models/chat_models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ import {
} from "../callbacks/manager.js";
import type { RunnableConfig } from "../runnables/config.js";
import type { BaseCache } from "../caches/base.js";
import { StructuredToolInterface } from "../tools/index.js";
import {
StructuredToolInterface,
StructuredToolParams,
} from "../tools/index.js";
import {
Runnable,
RunnableLambda,
Expand Down Expand Up @@ -123,6 +126,14 @@ export type LangSmithParams = {
ls_stop?: Array<string>;
};

export type BindToolsInput =
| StructuredToolInterface
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| Record<string, any>
| ToolDefinition
| RunnableToolLike
| StructuredToolParams;

/**
* Base class for chat models. It extends the BaseLanguageModel class and
* provides methods for generating chat based on input messages.
Expand Down Expand Up @@ -168,12 +179,7 @@ export abstract class BaseChatModel<
* @param kwargs Any additional parameters to bind.
*/
bindTools?(
tools: (
| StructuredToolInterface
| Record<string, unknown>
| ToolDefinition
| RunnableToolLike
)[],
tools: BindToolsInput[],
kwargs?: Partial<CallOptions>
): Runnable<BaseLanguageModelInput, OutputMessageType, CallOptions>;

Expand Down
17 changes: 17 additions & 0 deletions langchain-core/src/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,24 @@ export interface ToolParams extends BaseLangChainParams {
responseFormat?: ResponseFormat;
}

export interface StructuredToolParams
extends Pick<StructuredToolInterface, "name" | "schema"> {
/**
* An optional description of the tool to pass to the model.
*/
description?: string;
}

export interface StructuredToolInterface<T extends ZodObjectAny = ZodObjectAny>
extends RunnableInterface<
(z.output<T> extends string ? string : never) | z.input<T> | ToolCall,
ToolReturnType
> {
lc_namespace: string[];

/**
* A Zod schema representing the parameters of the tool.
*/
schema: T | z.ZodEffects<T>;

/**
Expand All @@ -75,8 +86,14 @@ export interface StructuredToolInterface<T extends ZodObjectAny = ZodObjectAny>
tags?: string[]
): Promise<ToolReturnType>;

/**
* The name of the tool.
*/
name: string;

/**
* A description of the tool.
*/
description: string;

returnDirect: boolean;
Expand Down
32 changes: 27 additions & 5 deletions langchain-core/src/utils/function_calling.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { zodToJsonSchema } from "zod-to-json-schema";
import { StructuredToolInterface } from "../tools/index.js";
import {
StructuredToolInterface,
StructuredToolParams,
} from "../tools/index.js";
import { FunctionDefinition, ToolDefinition } from "../language_models/base.js";
import { Runnable, RunnableToolLike } from "../runnables/base.js";
import { isZodSchema } from "./types/is_zod_schema.js";

/**
* Formats a `StructuredTool` or `RunnableToolLike` instance into a format
Expand All @@ -13,7 +17,7 @@ import { Runnable, RunnableToolLike } from "../runnables/base.js";
* @returns {FunctionDefinition} The inputted tool in OpenAI function format.
*/
export function convertToOpenAIFunction(
tool: StructuredToolInterface | RunnableToolLike,
tool: StructuredToolInterface | RunnableToolLike | StructuredToolParams,
fields?:
| {
/**
Expand Down Expand Up @@ -111,6 +115,25 @@ export function isRunnableToolLike(tool?: unknown): tool is RunnableToolLike {
);
}

/**
* Confirm whether or not the tool contains the necessary properties to be considered a `StructuredToolParams`.
*
* @param {unknown | undefined} tool The object to check if it is a `StructuredToolParams`.
* @returns {tool is StructuredToolParams} Whether the inputted object is a `StructuredToolParams`.
*/
export function isStructuredToolParams(
tool?: unknown
): tool is StructuredToolParams {
return (
!!tool &&
typeof tool === "object" &&
"name" in tool &&
"schema" in tool &&
// eslint-disable-next-line @typescript-eslint/no-explicit-any
isZodSchema(tool.schema as Record<string, any>)
);
}

/**
* Whether or not the tool is one of StructuredTool, RunnableTool or StructuredToolParams.
* It returns `is StructuredToolParams` since that is the most minimal interface of the three,
Expand All @@ -119,10 +142,9 @@ export function isRunnableToolLike(tool?: unknown): tool is RunnableToolLike {
* @param {unknown | undefined} tool The tool to check if it is a LangChain tool.
* @returns {tool is StructuredToolParams} Whether the inputted tool is a LangChain tool.
*/
export function isLangChainTool(
tool?: unknown
): tool is StructuredToolInterface {
export function isLangChainTool(tool?: unknown): tool is StructuredToolParams {
return (
isStructuredToolParams(tool) ||
isRunnableToolLike(tool) ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
isStructuredTool(tool as any)
Expand Down
9 changes: 2 additions & 7 deletions langchain/src/chat_models/universal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
import {
BaseChatModel,
BaseChatModelParams,
BindToolsInput,
type BaseChatModelCallOptions,
} from "@langchain/core/language_models/chat_models";
import { BaseMessage, type AIMessageChunk } from "@langchain/core/messages";
Expand Down Expand Up @@ -298,13 +299,7 @@ class _ConfigurableModel<
}

override bindTools(
tools: (
| StructuredToolInterface
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| Record<string, any>
| ToolDefinition
| RunnableToolLike
)[],
tools: BindToolsInput[],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
params?: Record<string, any>
): _ConfigurableModel<RunInput, CallOptions> {
Expand Down
36 changes: 15 additions & 21 deletions libs/langchain-anthropic/src/chat_models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,12 @@ import {
type ToolDefinition,
isOpenAITool,
} from "@langchain/core/language_models/base";
import { StructuredToolInterface } from "@langchain/core/tools";
import { zodToJsonSchema } from "zod-to-json-schema";
import { BaseLLMOutputParser } from "@langchain/core/output_parsers";
import {
Runnable,
RunnablePassthrough,
RunnableSequence,
RunnableToolLike,
} from "@langchain/core/runnables";
import { isZodSchema } from "@langchain/core/utils/types";
import { z } from "zod";
Expand All @@ -33,13 +31,9 @@ import type {
Tool as AnthropicTool,
} from "@anthropic-ai/sdk/resources/index.mjs";

import { isLangChainTool } from "@langchain/core/utils/function_calling";
import { AnthropicToolsOutputParser } from "./output_parsers.js";
import {
AnthropicToolChoice,
AnthropicToolTypes,
extractToolCallChunk,
handleToolChoice,
} from "./utils/tools.js";
import { extractToolCallChunk, handleToolChoice } from "./utils/tools.js";
import { _formatMessagesForAnthropic } from "./utils/message_inputs.js";
import {
_makeMessageChunkFromAnthropicEvent,
Expand All @@ -50,12 +44,14 @@ import {
AnthropicMessageStreamEvent,
AnthropicRequestOptions,
AnthropicStreamingMessageCreateParams,
AnthropicToolChoice,
ChatAnthropicToolType,
} from "./types.js";

export interface ChatAnthropicCallOptions
extends BaseChatModelCallOptions,
Pick<AnthropicInput, "streamUsage"> {
tools?: AnthropicToolTypes[];
tools?: ChatAnthropicToolType[];
/**
* Whether or not to specify what tool the model should use
* @default "auto"
Expand Down Expand Up @@ -344,21 +340,19 @@ export class ChatAnthropicMessages<
throw new Error(`Can not pass in a mix of tool schemas to ChatAnthropic`);
}

return (tools as StructuredToolInterface[]).map((tool) => ({
name: tool.name,
description: tool.description,
input_schema: zodToJsonSchema(tool.schema) as AnthropicTool.InputSchema,
}));
if (tools.every(isLangChainTool)) {
return tools.map((t) => ({
name: t.name,
description: t.description,
input_schema: zodToJsonSchema(t.schema) as AnthropicTool.InputSchema,
}));
}

throw new Error("Unsupported tool type passed to ChatAnthropic");
}

override bindTools(
tools: (
| AnthropicTool
| Record<string, unknown>
| StructuredToolInterface
| ToolDefinition
| RunnableToolLike
)[],
tools: ChatAnthropicToolType[],
kwargs?: Partial<CallOptions>
): Runnable<BaseLanguageModelInput, AIMessageChunk, CallOptions> {
return this.bind({
Expand Down
12 changes: 12 additions & 0 deletions libs/langchain-anthropic/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import Anthropic from "@anthropic-ai/sdk";
import type { Tool as AnthropicTool } from "@anthropic-ai/sdk/resources/index.mjs";
import { BindToolsInput } from "@langchain/core/language_models/chat_models";

export type AnthropicToolResponse = {
type: "tool_use";
Expand All @@ -17,3 +19,13 @@ export type AnthropicStreamingMessageCreateParams =
Anthropic.MessageCreateParamsStreaming;
export type AnthropicMessageStreamEvent = Anthropic.MessageStreamEvent;
export type AnthropicRequestOptions = Anthropic.RequestOptions;
export type AnthropicToolChoice =
| {
type: "tool";
name: string;
}
| "any"
| "auto"
| "none"
| string;
export type ChatAnthropicToolType = AnthropicTool | BindToolsInput;
26 changes: 2 additions & 24 deletions libs/langchain-anthropic/src/utils/tools.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,7 @@
import type {
MessageCreateParams,
Tool as AnthropicTool,
} from "@anthropic-ai/sdk/resources/index.mjs";
import { ToolDefinition } from "@langchain/core/language_models/base";
import type { MessageCreateParams } from "@anthropic-ai/sdk/resources/index.mjs";
import { AIMessageChunk } from "@langchain/core/messages";
import { ToolCallChunk } from "@langchain/core/messages/tool";
import { RunnableToolLike } from "@langchain/core/runnables";
import { StructuredToolInterface } from "@langchain/core/tools";

export type AnthropicToolChoice =
| {
type: "tool";
name: string;
}
| "any"
| "auto"
| "none"
| string;

export type AnthropicToolTypes =
| StructuredToolInterface
| AnthropicTool
| Record<string, unknown>
| ToolDefinition
| RunnableToolLike;
import { AnthropicToolChoice } from "../types.js";

export function handleToolChoice(
toolChoice?: AnthropicToolChoice
Expand Down
26 changes: 9 additions & 17 deletions libs/langchain-aws/src/chat_models.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import type { BaseMessage } from "@langchain/core/messages";
import { AIMessageChunk } from "@langchain/core/messages";
import type {
ToolDefinition,
BaseLanguageModelInput,
} from "@langchain/core/language_models/base";
import type { BaseLanguageModelInput } from "@langchain/core/language_models/base";
import { CallbackManagerForLLMRun } from "@langchain/core/callbacks/manager";
import {
type BaseChatModelParams,
Expand All @@ -13,7 +10,6 @@ import {
} from "@langchain/core/language_models/chat_models";
import type {
ToolConfiguration,
Tool as BedrockTool,
GuardrailConfiguration,
} from "@aws-sdk/client-bedrock-runtime";
import {
Expand All @@ -28,9 +24,12 @@ import {
DefaultProviderInit,
} from "@aws-sdk/credential-provider-node";
import type { DocumentType as __DocumentType } from "@smithy/types";
import { StructuredToolInterface } from "@langchain/core/tools";
import { Runnable, RunnableToolLike } from "@langchain/core/runnables";
import { ConverseCommandParams, CredentialType } from "./types.js";
import { Runnable } from "@langchain/core/runnables";
import {
ChatBedrockConverseToolType,
ConverseCommandParams,
CredentialType,
} from "./types.js";
import {
convertToConverseTools,
convertToBedrockToolChoice,
Expand Down Expand Up @@ -135,7 +134,7 @@ export interface ChatBedrockConverseCallOptions
*/
stop?: string[];

tools?: (StructuredToolInterface | ToolDefinition | BedrockTool)[];
tools?: ChatBedrockConverseToolType[];

/**
* Tool choice for the model. If passing a string, it must be "any", "auto" or the
Expand Down Expand Up @@ -280,14 +279,7 @@ export class ChatBedrockConverse
}

override bindTools(
tools: (
| StructuredToolInterface
| BedrockTool
| ToolDefinition
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| Record<string, any>
| RunnableToolLike
)[],
tools: ChatBedrockConverseToolType[],
kwargs?: Partial<this["ParsedCallOptions"]>
): Runnable<
BaseLanguageModelInput,
Expand Down
Loading

0 comments on commit 2edbcda

Please sign in to comment.