-
Notifications
You must be signed in to change notification settings - Fork 38
feat: add langchain decorator #356
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 1 commit
84604d2
2462ed5
927a5ea
765d63a
4b919cb
380490c
206dc19
ecd8248
ecd5cce
1f5d110
a8bb557
663f388
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # `@eggjs/tegg-langchain-decorator` | ||
|
|
||
| ## Install | ||
|
|
||
| ```shell | ||
| npm i --save @eggjs/tegg-langchain-decorator | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| { | ||
| "name": "@eggjs/tegg-langchain-decorator", | ||
| "version": "3.62.0", | ||
| "description": "tegg langchain decorator", | ||
| "main": "dist/index.js", | ||
| "files": [ | ||
| "dist/**/*.js", | ||
| "dist/**/*.d.ts" | ||
| ], | ||
| "typings": "dist/index.d.ts", | ||
| "keywords": [ | ||
| "egg", | ||
| "typescript", | ||
| "runtime", | ||
| "tegg" | ||
| ], | ||
| "scripts": { | ||
| "test": "cross-env NODE_ENV=test NODE_OPTIONS='--no-deprecation' mocha", | ||
| "clean": "tsc -b --clean", | ||
| "tsc": "npm run clean && tsc -p ./tsconfig.json", | ||
| "tsc:pub": "npm run clean && tsc -p ./tsconfig.pub.json", | ||
| "prepublishOnly": "npm run tsc:pub" | ||
| }, | ||
| "author": "killagu <[email protected]>", | ||
|
||
| "license": "MIT", | ||
| "homepage": "https://github.com/eggjs/tegg", | ||
| "bugs": { | ||
| "url": "https://github.com/eggjs/tegg/issues" | ||
| }, | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "[email protected]:eggjs/tegg.git", | ||
| "directory": "core/langchain-decorator" | ||
| }, | ||
| "engines": { | ||
| "node": ">=14.0.0" | ||
| }, | ||
| "dependencies": { | ||
| "@eggjs/core-decorator": "^3.62.0", | ||
| "@eggjs/tegg-common-util": "^3.62.0", | ||
| "@eggjs/tegg-metadata": "^3.62.0", | ||
| "@eggjs/tegg-types": "^3.62.0", | ||
| "@langchain/community": "^1.0.0", | ||
| "@langchain/core": "^1.0.0", | ||
| "@langchain/langgraph": "^1.0.0", | ||
| "@langchain/openai": "^1.0.0", | ||
| "langchain": "^1.0.0", | ||
| "lodash": "^4.17.21", | ||
| "pluralize": "^8.0.0" | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/mocha": "^10.0.1", | ||
| "@types/node": "^20.2.4", | ||
| "cross-env": "^7.0.3", | ||
| "mocha": "^10.2.0", | ||
| "ts-node": "^10.9.1", | ||
| "typescript": "^5.0.4" | ||
| }, | ||
| "gitHead": "5f24bacd9131435188be15568d86ef4575f85636" | ||
akitaSummer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { EggProtoImplClass } from '@eggjs/tegg'; | ||
| import { BoundModelInfoUtil } from '../util/BoundModelInfoUtil'; | ||
| import { BoundModelMetadata } from '../model/BoundModelMetadata'; | ||
|
|
||
| export class BoundModelMetaBuilder { | ||
| private readonly clazz: EggProtoImplClass; | ||
|
|
||
| constructor(clazz: EggProtoImplClass) { | ||
| this.clazz = clazz; | ||
| } | ||
|
|
||
| build(): BoundModelMetadata | undefined { | ||
| const metadata = BoundModelInfoUtil.getBoundModelMetadata(this.clazz); | ||
| if (metadata) { | ||
| return new BoundModelMetadata(metadata); | ||
| } | ||
| } | ||
|
|
||
| static create(clazz: EggProtoImplClass): BoundModelMetaBuilder { | ||
| return new BoundModelMetaBuilder(clazz); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { EggProtoImplClass } from '@eggjs/tegg'; | ||
| import { GraphEdgeInfoUtil } from '../util/GraphEdgeInfoUtil'; | ||
| import { GraphEdgeMetadata } from '../model/GraphEdgeMetadata'; | ||
|
|
||
| export class GraphEdgeMetaBuilder { | ||
| private readonly clazz: EggProtoImplClass; | ||
|
|
||
| constructor(clazz: EggProtoImplClass) { | ||
| this.clazz = clazz; | ||
| } | ||
|
|
||
| build(): GraphEdgeMetadata | undefined { | ||
| const metadata = GraphEdgeInfoUtil.getGraphEdgeMetadata(this.clazz); | ||
| if (metadata) { | ||
| return new GraphEdgeMetadata(metadata); | ||
| } | ||
| } | ||
|
|
||
| static create(clazz: EggProtoImplClass): GraphEdgeMetaBuilder { | ||
| return new GraphEdgeMetaBuilder(clazz); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { EggProtoImplClass } from '@eggjs/tegg'; | ||
| import { GraphInfoUtil } from '../util/GraphInfoUtil'; | ||
| import { GraphMetadata } from '../model/GraphMetadata'; | ||
|
|
||
| export class GraphMetaBuilder { | ||
| private readonly clazz: EggProtoImplClass; | ||
|
|
||
| constructor(clazz: EggProtoImplClass) { | ||
| this.clazz = clazz; | ||
| } | ||
|
|
||
| build(): GraphMetadata | undefined { | ||
| const metadata = GraphInfoUtil.getGraphMetadata(this.clazz); | ||
| if (metadata) { | ||
| return new GraphMetadata(metadata); | ||
| } | ||
| } | ||
|
|
||
| static create(clazz: EggProtoImplClass): GraphMetaBuilder { | ||
| return new GraphMetaBuilder(clazz); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { EggProtoImplClass } from '@eggjs/tegg'; | ||
| import { GraphNodeInfoUtil } from '../util/GraphNodeInfoUtil'; | ||
| import { GraphNodeMetadata } from '../model/GraphNodeMetadata'; | ||
|
|
||
| export class GraphNodeMetaBuilder { | ||
| private readonly clazz: EggProtoImplClass; | ||
|
|
||
| constructor(clazz: EggProtoImplClass) { | ||
| this.clazz = clazz; | ||
| } | ||
|
|
||
| build(): GraphNodeMetadata | undefined { | ||
| const metadata = GraphNodeInfoUtil.getGraphNodeMetadata(this.clazz); | ||
| if (metadata) { | ||
| return new GraphNodeMetadata(metadata); | ||
| } | ||
| } | ||
|
|
||
| static create(clazz: EggProtoImplClass): GraphNodeMetaBuilder { | ||
| return new GraphNodeMetaBuilder(clazz); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { EggProtoImplClass } from '@eggjs/tegg'; | ||
| import { GraphToolInfoUtil } from '../util/GraphToolInfoUtil'; | ||
| import { GraphToolMetadata } from '../model/GraphToolMetadata'; | ||
|
|
||
| export class GraphToolMetaBuilder { | ||
| private readonly clazz: EggProtoImplClass; | ||
|
|
||
| constructor(clazz: EggProtoImplClass) { | ||
| this.clazz = clazz; | ||
| } | ||
|
|
||
| build(): GraphToolMetadata | undefined { | ||
| const metadata = GraphToolInfoUtil.getGraphToolMetadata(this.clazz); | ||
| if (metadata) { | ||
| return new GraphToolMetadata(metadata); | ||
| } | ||
| } | ||
|
|
||
| static create(clazz: EggProtoImplClass): GraphToolMetaBuilder { | ||
| return new GraphToolMetaBuilder(clazz); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import { StackUtil } from '@eggjs/tegg-common-util'; | ||
| import { | ||
| AccessLevel, | ||
| SingletonProto, | ||
| PrototypeUtil, | ||
| EggProtoImplClass, | ||
| } from '@eggjs/tegg'; | ||
|
|
||
| import { IBoundModelMetadata } from '../model/BoundModelMetadata'; | ||
| import { BoundModelInfoUtil } from '../util/BoundModelInfoUtil'; | ||
| import { BaseChatOpenAI, ChatOpenAICallOptions } from '@langchain/openai'; | ||
|
|
||
|
|
||
| export function BoundModel(params: IBoundModelMetadata) { | ||
| return (constructor: EggProtoImplClass) => { | ||
| const func = SingletonProto({ | ||
| accessLevel: params?.accessLevel ?? AccessLevel.PUBLIC, | ||
| name: params?.name, | ||
| }); | ||
| func(constructor); | ||
| PrototypeUtil.setFilePath(constructor, StackUtil.getCalleeFromStack(false, 5)); | ||
|
|
||
| BoundModelInfoUtil.setBoundModelMetadata(params, constructor); | ||
| }; | ||
akitaSummer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| type BaseChatModel<T extends ChatOpenAICallOptions = ChatOpenAICallOptions> = InstanceType<typeof BaseChatOpenAI<T>> extends infer C | ||
| ? C : never; | ||
|
|
||
| export type TeggBoundModel<S, CallOptions extends ChatOpenAICallOptions = ChatOpenAICallOptions> = S & ReturnType<NonNullable<BaseChatModel<CallOptions>['bindTools']>>; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| import { AnnotationRoot, CompiledStateGraph, StateDefinition, StateGraph, StateType, UpdateType } from '@langchain/langgraph'; | ||
| import { | ||
| AccessLevel, | ||
| SingletonProto, | ||
| PrototypeUtil, | ||
| EggProtoImplClass, | ||
| } from '@eggjs/tegg'; | ||
|
|
||
| import { IGraphMetadata } from '../model/GraphMetadata'; | ||
| import { GraphInfoUtil } from '../util/GraphInfoUtil'; | ||
| import { StackUtil } from '@eggjs/tegg-common-util'; | ||
| export function Graph<N extends string = '', S extends StateDefinition = StateDefinition>(params: IGraphMetadata) { | ||
| return (constructor: EggProtoImplClass<AbstractStateGraph<N, S>>) => { | ||
| const func = SingletonProto({ | ||
| accessLevel: params?.accessLevel ?? AccessLevel.PUBLIC, | ||
| name: params?.name, | ||
| }); | ||
| func(constructor); | ||
| PrototypeUtil.setFilePath(constructor, StackUtil.getCalleeFromStack(false, 5)); | ||
|
|
||
| GraphInfoUtil.setGraphMetadata(params, constructor); | ||
| }; | ||
akitaSummer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| export interface IGraph<N extends string = '', S extends StateDefinition = StateDefinition> extends StateGraph<S, AnnotationRoot<S>['State'], UpdateType<S>, N> { | ||
| build?(): Promise<CompiledStateGraph<StateType<StateDefinition>, UpdateType<StateDefinition>, string, StateDefinition, StateDefinition, StateDefinition> | undefined>; | ||
| } | ||
akitaSummer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| export abstract class AbstractStateGraph<N extends string = '', S extends StateDefinition = StateDefinition> extends StateGraph<S, AnnotationRoot<S>['State'], UpdateType<S>, N> implements IGraph<N, S> { | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| private _names: N; | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| private _state: S; | ||
| } | ||
|
|
||
| export type TeggCompiledStateGraph<G> = G extends AbstractStateGraph<infer N, infer S> ? CompiledStateGraph<StateType<S>, UpdateType<S>, N, S, S> : never; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import { | ||
| AccessLevel, | ||
| SingletonProto, | ||
| PrototypeUtil, | ||
| EggProtoImplClass, | ||
| } from '@eggjs/tegg'; | ||
| import { StackUtil } from '@eggjs/tegg-common-util'; | ||
|
|
||
| import { IGraphEdgeMetadata } from '../model/GraphEdgeMetadata'; | ||
| import { GraphEdgeInfoUtil } from '../util/GraphEdgeInfoUtil'; | ||
| import { AnnotationRoot, StateDefinition, UpdateType } from '@langchain/langgraph'; | ||
|
|
||
| /** | ||
| * @description GraphEdge decorator | ||
| * @param {IGraphEdgeMetadata} params | ||
|
Check warning on line 15 in core/langchain-decorator/src/decorator/GraphEdge.ts
|
||
| * @example | ||
| * ```ts | ||
| * @GraphEdge({ | ||
| * fromNodeName: 'start', // 标记启动点,如果只有 fromNodeName 和 toNodeNames,那么就是单向边 | ||
| * toNodeNames: ['end'], // 标记结束点,可以是多个,多个的时候就必须要实现 execute | ||
| * }) | ||
| * ``` | ||
| * @return {Function} | ||
|
Check warning on line 23 in core/langchain-decorator/src/decorator/GraphEdge.ts
|
||
| */ | ||
| export function GraphEdge<S extends StateDefinition = StateDefinition, N extends string = '__start__' | '__end__'>(params: IGraphEdgeMetadata) { | ||
| return (constructor: EggProtoImplClass<IGraphEdge<S, N>>) => { | ||
| const func = SingletonProto({ | ||
| accessLevel: params?.accessLevel ?? AccessLevel.PUBLIC, | ||
| name: params?.name, | ||
| }); | ||
| func(constructor); | ||
| PrototypeUtil.setFilePath(constructor, StackUtil.getCalleeFromStack(false, 5)); | ||
|
|
||
| GraphEdgeInfoUtil.setGraphEdgeMetadata(params, constructor); | ||
| }; | ||
akitaSummer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| export type GraphStateType<A extends StateDefinition = StateDefinition> = AnnotationRoot<A>['State']; | ||
|
|
||
| export type GraphUpdateType<A extends StateDefinition = StateDefinition> = UpdateType<A>; | ||
|
|
||
| export interface IGraphEdge<S extends StateDefinition = StateDefinition, N extends string = '__start__' | '__end__'> { | ||
| execute?(state: AnnotationRoot<S>['State']): Promise<N | N[]>; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| // import type { EggProtoImplClass } from '@alipay/tegg-types'; | ||
akitaSummer marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| import { StackUtil } from '@eggjs/tegg-common-util'; | ||
| import { | ||
| AccessLevel, | ||
| SingletonProto, | ||
| PrototypeUtil, | ||
| EggProtoImplClass, | ||
| } from '@eggjs/tegg'; | ||
|
|
||
| import { IGraphNodeMetadata } from '../model/GraphNodeMetadata'; | ||
| import { GraphNodeInfoUtil } from '../util/GraphNodeInfoUtil'; | ||
| import { AnnotationRoot, StateDefinition, UpdateType } from '@langchain/langgraph'; | ||
| import { ConfigurableModel } from 'langchain/dist/chat_models/universal.js'; | ||
akitaSummer marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| import { ToolNode } from '@langchain/langgraph/dist/prebuilt'; | ||
|
|
||
akitaSummer marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| export function GraphNode<S extends StateDefinition = StateDefinition>(params: IGraphNodeMetadata) { | ||
| return (constructor: EggProtoImplClass<IGraphNode<S> | TeggToolNode>) => { | ||
| const func = SingletonProto({ | ||
| accessLevel: params?.accessLevel ?? AccessLevel.PUBLIC, | ||
| name: params?.name, | ||
| }); | ||
| func(constructor); | ||
| PrototypeUtil.setFilePath(constructor, StackUtil.getCalleeFromStack(false, 5)); | ||
|
|
||
| GraphNodeInfoUtil.setGraphNodeMetadata(params, constructor); | ||
| }; | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| export interface IGraphNode<S extends StateDefinition = StateDefinition, T = any> { | ||
|
|
||
| // execute(state: T extends AbstractStateGraph<infer S> ? GraphStateType<S> : never): Promise<GraphUpdateType<T> extends object ? GraphUpdateType<T> & Record<string, any> : GraphUpdateType<T>>; | ||
akitaSummer marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| execute(state: AnnotationRoot<S>['State']): Promise<UpdateType<S> & Record<string, any>> | Promise<ToolNode<T>>; | ||
|
|
||
| build?: (tools: Parameters<ConfigurableModel['bindTools']>['0']) => Promise<ConfigurableModel>; | ||
| } | ||
|
|
||
| export class TeggToolNode implements IGraphNode { | ||
| toolNode: ToolNode; | ||
|
|
||
| async execute() { | ||
| return this.toolNode; | ||
| } | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| // import type { ToolSchemaBase, DynamicStructuredTool } from '../../core/tools.js'; | ||
akitaSummer marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| import { StackUtil } from '@eggjs/tegg-common-util'; | ||
| import { | ||
| AccessLevel, | ||
| SingletonProto, | ||
| PrototypeUtil, | ||
| EggProtoImplClass, | ||
| } from '@eggjs/tegg'; | ||
|
|
||
| import { IGraphToolMetadata } from '../model/GraphToolMetadata'; | ||
| import { GraphToolInfoUtil } from '../util/GraphToolInfoUtil'; | ||
| import { DynamicStructuredTool, ToolSchemaBase } from '@langchain/core/dist/tools'; | ||
akitaSummer marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| export function GraphTool<ToolSchema = ToolSchemaBase>(params: IGraphToolMetadata) { | ||
| return (constructor: EggProtoImplClass<IGraphTool<ToolSchema>>) => { | ||
akitaSummer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const func = SingletonProto({ | ||
| accessLevel: params?.accessLevel ?? AccessLevel.PUBLIC, | ||
| name: params?.name, | ||
| }); | ||
| func(constructor); | ||
| PrototypeUtil.setFilePath(constructor, StackUtil.getCalleeFromStack(false, 5)); | ||
|
|
||
| GraphToolInfoUtil.setGraphToolMetadata(params, constructor); | ||
| }; | ||
| } | ||
|
|
||
| export interface IGraphTool<ToolSchema = ToolSchemaBase> { | ||
|
|
||
| execute: DynamicStructuredTool<ToolSchema>['func']; | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.