Skip to content

Commit

Permalink
community[minor],langchain[minor]: Move base classes and reference im…
Browse files Browse the repository at this point in the history
…plementations to core (langchain-ai#5187)

* Move toolkit declaration to core

* Move more reference implementations to core

* Move BaseChatMemory

* Revert BaseChatMemory move

* core[patch],langchain[patch]: Refactor self query (langchain-ai#5192)

* Move BaseChain and LLMChain to legacy entrypoint in core

* Fix build

* Add deprecation strings

* Revert BaseChain and LLMChain moves

* Rename

* Refactor

* Revert

* Update imports

* Remove type

* Remove peer dep

* Update lock

* Bump deps

* Fix
  • Loading branch information
jacoblee93 authored Apr 24, 2024
1 parent 7fae59b commit df43448
Show file tree
Hide file tree
Showing 22 changed files with 96 additions and 984 deletions.
2 changes: 1 addition & 1 deletion langchain/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1513,7 +1513,7 @@
"dependencies": {
"@anthropic-ai/sdk": "^0.9.1",
"@langchain/community": "~0.0.47",
"@langchain/core": "~0.1.56",
"@langchain/core": "~0.1.60",
"@langchain/openai": "~0.0.28",
"@langchain/textsplitters": "~0.0.0",
"binary-extensions": "^2.2.0",
Expand Down
21 changes: 13 additions & 8 deletions langchain/src/chains/query_constructor/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { BaseLanguageModelInterface } from "@langchain/core/language_models/base";
import { z } from "zod";
import type { BaseLanguageModelInterface } from "@langchain/core/language_models/base";
import {
Example,
interpolateFString,
Expand All @@ -21,7 +21,6 @@ import {
DEFAULT_SUFFIX,
EXAMPLE_PROMPT,
} from "./prompt.js";
import { LLMChain } from "../llm_chain.js";
import { AsymmetricStructuredOutputParser } from "../../output_parsers/structured.js";
import { AttributeInfo } from "../../schema/query_constructor.js";

Expand Down Expand Up @@ -168,7 +167,7 @@ function _getPrompt(
/**
* A type that represents options for the query constructor chain.
*/
export type QueryConstructorChainOptions = {
export type QueryConstructorRunnableOptions = {
llm: BaseLanguageModelInterface;
documentContents: string;
attributeInfo: AttributeInfo[];
Expand All @@ -177,16 +176,22 @@ export type QueryConstructorChainOptions = {
allowedOperators?: Operator[];
};

export function loadQueryConstructorChain(opts: QueryConstructorChainOptions) {
/** @deprecated */
export type QueryConstructorChainOptions = QueryConstructorRunnableOptions;

export function loadQueryConstructorRunnable(
opts: QueryConstructorRunnableOptions
) {
const prompt = _getPrompt(
opts.documentContents,
opts.attributeInfo,
opts.allowedComparators,
opts.allowedOperators,
opts.examples
);
return new LLMChain({
llm: opts.llm,
prompt,
});
const outputParser = StructuredQueryOutputParser.fromComponents(
opts.allowedComparators,
opts.allowedOperators
);
return prompt.pipe(opts.llm).pipe(outputParser);
}
187 changes: 1 addition & 186 deletions langchain/src/chains/query_constructor/ir.ts
Original file line number Diff line number Diff line change
@@ -1,186 +1 @@
import { VectorStore } from "@langchain/core/vectorstores";

/**
* Represents logical AND operator.
*/
export type AND = "and";
/**
* Represents logical OR operator.
*/
export type OR = "or";
/**
* Represents logical NOT operator.
*/
export type NOT = "not";

/**
* Represents a logical operator which can be AND, OR, or NOT.
*/
export type Operator = AND | OR | NOT;

/**
* Represents equality comparison operator.
*/
export type EQ = "eq";
/**
* Represents inequality comparison operator.
*/
export type NE = "ne";
/**
* Represents less than comparison operator.
*/
export type LT = "lt";
/**
* Represents greater than comparison operator.
*/
export type GT = "gt";
/**
* Represents less than or equal to comparison operator.
*/
export type LTE = "lte";
/**
* Represents greater than or equal to comparison operator.
*/
export type GTE = "gte";

/**
* Represents a comparison operator which can be EQ, NE, LT, GT, LTE, or
* GTE.
*/
export type Comparator = EQ | NE | LT | GT | LTE | GTE;

export const Operators: { [key: string]: Operator } = {
and: "and",
or: "or",
not: "not",
};

export const Comparators: { [key: string]: Comparator } = {
eq: "eq",
ne: "ne",
lt: "lt",
gt: "gt",
lte: "lte",
gte: "gte",
};

/**
* Represents the result of visiting an operation or comparison
* expression.
*/
export type VisitorResult = VisitorOperationResult | VisitorComparisonResult;

/**
* Represents the result of visiting an operation expression.
*/
export type VisitorOperationResult = {
[operator: string]: VisitorResult[];
};

/**
* Represents the result of visiting a comparison expression.
*/
export type VisitorComparisonResult = {
[attr: string]: {
[comparator: string]: string | number;
};
};

/**
* Represents the result of visiting a structured query expression.
*/
export type VisitorStructuredQueryResult = {
filter?: VisitorComparisonResult | VisitorOperationResult;
};

/**
* Abstract class for visiting expressions. Subclasses must implement
* visitOperation, visitComparison, and visitStructuredQuery methods.
*/
export abstract class Visitor<T extends VectorStore = VectorStore> {
declare VisitOperationOutput: object;

declare VisitComparisonOutput: object;

declare VisitStructuredQueryOutput: { filter?: T["FilterType"] };

abstract allowedOperators: Operator[];

abstract allowedComparators: Comparator[];

abstract visitOperation(operation: Operation): this["VisitOperationOutput"];

abstract visitComparison(
comparison: Comparison
): this["VisitComparisonOutput"];

abstract visitStructuredQuery(
structuredQuery: StructuredQuery
): this["VisitStructuredQueryOutput"];
}

/**
* Abstract class representing an expression. Subclasses must implement
* the exprName property and the accept method.
*/
export abstract class Expression {
abstract exprName: "Operation" | "Comparison" | "StructuredQuery";

accept(visitor: Visitor) {
if (this.exprName === "Operation") {
return visitor.visitOperation(this as unknown as Operation);
} else if (this.exprName === "Comparison") {
return visitor.visitComparison(this as unknown as Comparison);
} else if (this.exprName === "StructuredQuery") {
return visitor.visitStructuredQuery(this as unknown as StructuredQuery);
} else {
throw new Error("Unknown Expression type");
}
}
}

/**
* Abstract class representing a filter directive. It extends the
* Expression class.
*/
export abstract class FilterDirective extends Expression {}

/**
* Class representing a comparison filter directive. It extends the
* FilterDirective class.
*/
export class Comparison extends FilterDirective {
exprName = "Comparison" as const;

constructor(
public comparator: Comparator,
public attribute: string,
public value: string | number
) {
super();
}
}

/**
* Class representing an operation filter directive. It extends the
* FilterDirective class.
*/
export class Operation extends FilterDirective {
exprName = "Operation" as const;

constructor(public operator: Operator, public args?: FilterDirective[]) {
super();
}
}

/**
* Class representing a structured query expression. It extends the
* Expression class.
*/
export class StructuredQuery extends Expression {
exprName = "StructuredQuery" as const;

constructor(public query: string, public filter?: FilterDirective) {
super();
}
}
export * from "@langchain/core/structured_query";
2 changes: 1 addition & 1 deletion langchain/src/chains/query_constructor/prompt.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PromptTemplate } from "@langchain/core/prompts";
import { PromptTemplate } from "../../prompts/index.js";

export const SONG_DATA_SOURCE = `\
\`\`\`json
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { test } from "@jest/globals";
import { OpenAI } from "@langchain/openai";
import { loadQueryConstructorChain } from "../index.js";
import { loadQueryConstructorRunnable } from "../index.js";
import {
Comparators,
Comparison,
Expand Down Expand Up @@ -76,54 +76,44 @@ test("Query Chain Test", async () => {

const allowedComparators = Object.values(Comparators);
const allowedOperators = Object.values(Operators);
const llm = new OpenAI({ modelName: "gpt-3.5-turbo", temperature: 0 });
const queryChain = loadQueryConstructorChain({
const llm = new OpenAI({
modelName: "gpt-3.5-turbo-instruct",
temperature: 0,
});
const queryChain = loadQueryConstructorRunnable({
llm,
documentContents,
attributeInfo,
allowedComparators,
allowedOperators,
});

const c1 = queryChain.call({
const c1 = queryChain.invoke({
query: "Which movies are less than 90 minutes?",
});
const c3 = queryChain.call({
const c3 = queryChain.invoke({
query: "Which movies are rated higher than 8.5?",
});
const c4 = queryChain.call({
const c4 = queryChain.invoke({
query: "Which movies are directed by Greta Gerwig?",
});
const c5 = queryChain.call({
const c5 = queryChain.invoke({
query:
"Which movies are either comedy or drama and are less than 90 minutes?",
});

const [
{ [queryChain.outputKey]: r1 },
{ [queryChain.outputKey]: r3 },
{ [queryChain.outputKey]: r4 },
{ [queryChain.outputKey]: r5 },
] = await Promise.all([c1, c3, c4, c5]);
const [r1, r3, r4, r5] = await Promise.all([c1, c3, c4, c5]);

expect(r1).toMatchObject(sq1);
expect(r3).toMatchObject(sq3);
expect(r4).toMatchObject(sq4);
expect(r5).toMatchObject(sq5);
const testTranslator = new BasicTranslator();

const { filter: parsedFilter1 } = testTranslator.visitStructuredQuery(
r1 as StructuredQuery
);
const { filter: parsedFilter3 } = testTranslator.visitStructuredQuery(
r3 as StructuredQuery
);
const { filter: parsedFilter4 } = testTranslator.visitStructuredQuery(
r4 as StructuredQuery
);
const { filter: parsedFilter5 } = testTranslator.visitStructuredQuery(
r5 as StructuredQuery
);
const { filter: parsedFilter1 } = testTranslator.visitStructuredQuery(r1);
const { filter: parsedFilter3 } = testTranslator.visitStructuredQuery(r3);
const { filter: parsedFilter4 } = testTranslator.visitStructuredQuery(r4);
const { filter: parsedFilter5 } = testTranslator.visitStructuredQuery(r5);

expect(parsedFilter1).toMatchObject(filter1);
expect(parsedFilter3).toMatchObject(filter3);
Expand Down
3 changes: 2 additions & 1 deletion langchain/src/output_parsers/expression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { BaseOutputParser } from "@langchain/core/output_parsers";
import { MasterHandler } from "./expression_type_handlers/factory.js";
import { ParsedType } from "./expression_type_handlers/types.js";
import { ASTParser } from "./expression_type_handlers/base.js";

/**
* okay so we need to be able to handle the following cases:
* We need to be able to handle the following cases:
* ExpressionStatement
* CallExpression
* Identifier | MemberExpression
Expand Down
Loading

0 comments on commit df43448

Please sign in to comment.