-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
core[minor]: RunnableToolLike (#6029)
* init * RunnableToolLike * implemented without generics * figured out generics typing almost * use runnable binding instead of lambda * use RunInput generic in a way... * cr * more test * more tests and start docs * drop docs * allow runnabletoollike in bindTools * mark as type in re-export * drop default description * update isRunnableToolLike to check lc_name * added standard test * cr * default to zod description * fix some jsdoc
- Loading branch information
1 parent
6111718
commit 2eb699d
Showing
22 changed files
with
373 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
139 changes: 139 additions & 0 deletions
139
langchain-core/src/runnables/tests/runnable_tools.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
import { z } from "zod"; | ||
import { RunnableLambda, RunnableToolLike } from "../base.js"; | ||
|
||
test("Runnable asTool works", async () => { | ||
const schema = z.object({ | ||
foo: z.string(), | ||
}); | ||
const runnable = RunnableLambda.from<z.infer<typeof schema>, string>( | ||
(input, config) => { | ||
return `${input.foo}${config?.configurable.foo}`; | ||
} | ||
); | ||
const tool = runnable.asTool({ | ||
schema, | ||
}); | ||
|
||
expect(tool).toBeInstanceOf(RunnableToolLike); | ||
expect(tool.schema).toBe(schema); | ||
expect(tool.name).toBe(runnable.getName()); | ||
}); | ||
|
||
test("Runnable asTool works with all populated fields", async () => { | ||
const schema = z.object({ | ||
foo: z.string(), | ||
}); | ||
const runnable = RunnableLambda.from<z.infer<typeof schema>, string>( | ||
(input, config) => { | ||
return `${input.foo}${config?.configurable.foo}`; | ||
} | ||
); | ||
const tool = runnable.asTool({ | ||
schema, | ||
name: "test", | ||
description: "test", | ||
}); | ||
|
||
expect(tool).toBeInstanceOf(RunnableToolLike); | ||
expect(tool.schema).toBe(schema); | ||
expect(tool.description).toBe("test"); | ||
expect(tool.name).toBe("test"); | ||
}); | ||
|
||
test("Runnable asTool can invoke", async () => { | ||
const schema = z.object({ | ||
foo: z.string(), | ||
}); | ||
const runnable = RunnableLambda.from<z.infer<typeof schema>, string>( | ||
(input, config) => { | ||
return `${input.foo}${config?.configurable.foo}`; | ||
} | ||
); | ||
const tool = runnable.asTool({ | ||
schema, | ||
}); | ||
|
||
const toolResponse = await tool.invoke( | ||
{ | ||
foo: "bar", | ||
}, | ||
{ | ||
configurable: { | ||
foo: "bar", | ||
}, | ||
} | ||
); | ||
|
||
expect(toolResponse).toBe("barbar"); | ||
}); | ||
|
||
test("asTool should type error with mismatched schema", async () => { | ||
// asTool infers the type of the Zod schema from the existing runnable's RunInput generic. | ||
// If the Zod schema does not match the RunInput, it should throw a type error. | ||
const schema = z.object({ | ||
foo: z.string(), | ||
}); | ||
const runnable = RunnableLambda.from<{ bar: string }, string>( | ||
(input, config) => { | ||
return `${input.bar}${config?.configurable.foo}`; | ||
} | ||
); | ||
runnable.asTool({ | ||
// @ts-expect-error - Should error. If this does not give a type error, the generics/typing of `asTool` is broken. | ||
schema, | ||
}); | ||
}); | ||
|
||
test("Create a runnable tool directly from RunnableToolLike", async () => { | ||
const schema = z.object({ | ||
foo: z.string(), | ||
}); | ||
const adderFunc = (_: z.infer<typeof schema>): Promise<boolean> => { | ||
return Promise.resolve(true); | ||
}; | ||
const tool = new RunnableToolLike({ | ||
schema, | ||
name: "test", | ||
description: "test", | ||
bound: RunnableLambda.from(adderFunc), | ||
}); | ||
|
||
const result = await tool.invoke({ foo: "bar" }); | ||
expect(result).toBe(true); | ||
}); | ||
|
||
test("asTool can take a single string input", async () => { | ||
const firstRunnable = RunnableLambda.from<string, string>((input) => { | ||
return `${input}a`; | ||
}); | ||
const secondRunnable = RunnableLambda.from<string, string>((input) => { | ||
return `${input}z`; | ||
}); | ||
|
||
const runnable = firstRunnable.pipe(secondRunnable); | ||
const asTool = runnable.asTool({ | ||
schema: z.string(), | ||
}); | ||
|
||
const result = await asTool.invoke("b"); | ||
expect(result).toBe("baz"); | ||
}); | ||
|
||
test("Runnable asTool uses Zod schema description if not provided", async () => { | ||
const description = "Test schema"; | ||
const schema = z | ||
.object({ | ||
foo: z.string(), | ||
}) | ||
.describe(description); | ||
const runnable = RunnableLambda.from<z.infer<typeof schema>, string>( | ||
(input, config) => { | ||
return `${input.foo}${config?.configurable.foo}`; | ||
} | ||
); | ||
const tool = runnable.asTool({ | ||
schema, | ||
}); | ||
|
||
expect(tool.description).toBe(description); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import type { z } from "zod"; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export type ZodAny = z.ZodObject<any, any, any, any>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.