Skip to content

Commit

Permalink
Update docstrings, improve API refs (#369)
Browse files Browse the repository at this point in the history
  • Loading branch information
jacoblee93 authored Aug 24, 2024
1 parent a7e1458 commit 421d255
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 14 deletions.
5 changes: 0 additions & 5 deletions docs/docs/concepts/low_level.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ A super-step can be considered a single iteration over the graph nodes. Nodes th

The `StateGraph` class is the main graph class to uses. This is parameterized by a user defined `State` object. (defined using the `Annotation` object and passed as the first argument)


### MessageGraph

The `MessageGraph` class is a special type of graph. The `State` of a `MessageGraph` is ONLY a list of messages. This class is rarely used except for chatbots, as most applications require the `State` to be more complex than a list of messages.

### Compiling your graph

To build your graph, you first define the [state](#state), you then add [nodes](#nodes) and [edges](#edges), and then you compile it. What exactly is compiling your graph and why is it needed?
Expand Down
2 changes: 2 additions & 0 deletions libs/checkpoint/src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export function deepCopy<T>(obj: T): T {
return newObj as T;
}

/** @hidden */
export function emptyCheckpoint(): Checkpoint {
return {
v: 1,
Expand All @@ -84,6 +85,7 @@ export function emptyCheckpoint(): Checkpoint {
};
}

/** @hidden */
export function copyCheckpoint(checkpoint: ReadonlyCheckpoint): Checkpoint {
return {
v: checkpoint.v,
Expand Down
99 changes: 90 additions & 9 deletions libs/langgraph/src/graph/annotation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ export type NodeType<SD extends StateDefinition> = RunnableLike<
UpdateType<SD>
>;

/** @ignore */
export interface AnnotationFunction {
<ValueType>(): LastValue<ValueType>;
<ValueType, UpdateType = ValueType>(
annotation: SingleReducer<ValueType, UpdateType>
): BinaryOperatorAggregate<ValueType, UpdateType>;
Root: <S extends StateDefinition>(sd: S) => AnnotationRoot<S>;
}

/**
* Should not be instantiated directly. See {@link Annotation}.
* @internal
*/
export class AnnotationRoot<SD extends StateDefinition> {
lc_graph_name = "AnnotationRoot";

Expand All @@ -62,14 +75,81 @@ export class AnnotationRoot<SD extends StateDefinition> {
}
}

// TODO: Add docstring
export function Annotation<ValueType>(): LastValue<ValueType>;

export function Annotation<ValueType, UpdateType = ValueType>(
annotation: SingleReducer<ValueType, UpdateType>
): BinaryOperatorAggregate<ValueType, UpdateType>;

export function Annotation<ValueType, UpdateType = ValueType>(
/**
* Helper that instantiates channels within a StateGraph state.
*
* Can be used as a field in an {@link Annotation.Root} wrapper in one of two ways:
* 1. **Directly**: Creates a channel that stores the most recent value returned from a node.
* 2. **With a reducer**: Creates a channel that applies the reducer on a node's return value.
*
* @example
* ```ts
* import { StateGraph, Annotation } from "@langchain/langgraph";
*
* // Define a state with a single string key named "currentOutput"
* const SimpleAnnotation = Annotation.Root({
* currentOutput: Annotation<string>,
* });
*
* const graphBuilder = new StateGraph(SimpleAnnotation);
*
* // A node in the graph that returns an object with a "currentOutput" key
* // replaces the value in the state. You can get the state type as shown below:
* const myNode = (state: typeof SimpleAnnotation.State) => {
* return {
* currentOutput: "some_new_value",
* };
* }
*
* const graph = graphBuilder
* .addNode("myNode", myNode)
* ...
* .compile();
* ```
*
* @example
* ```ts
* import { type BaseMessage, AIMessage } from "@langchain/core/messages";
* import { StateGraph, Annotation } from "@langchain/langgraph";
*
* // Define a state with a single key named "messages" that will
* // combine a returned BaseMessage or arrays of BaseMessages
* const AnnotationWithReducer = Annotation.Root({
* messages: Annotation<BaseMessage[]>({
* // Different types are allowed for updates
* reducer: (left: BaseMessage[], right: BaseMessage | BaseMessage[]) => {
* if (Array.isArray(right)) {
* return left.concat(right);
* }
* return left.concat([right]);
* },
* default: () => [],
* }),
* });
*
* const graphBuilder = new StateGraph(AnnotationWithReducer);
*
* // A node in the graph that returns an object with a "messages" key
* // will update the state by combining the existing value with the returned one.
* const myNode = (state: typeof AnnotationWithReducer.State) => {
* return {
* messages: [new AIMessage("Some new response")],
* };
* };
*
* const graph = graphBuilder
* .addNode("myNode", myNode)
* ...
* .compile();
* ```
* @namespace
* @property Root
* Helper function that instantiates a StateGraph state. See {@link Annotation} for usage.
*/
export const Annotation: AnnotationFunction = function <
ValueType,
UpdateType = ValueType
>(
annotation?: SingleReducer<ValueType, UpdateType>
): BaseChannel<ValueType, UpdateType> {
if (annotation) {
Expand All @@ -78,7 +158,8 @@ export function Annotation<ValueType, UpdateType = ValueType>(
// @ts-expect-error - Annotation without reducer
return new LastValue<ValueType>();
}
}
} as AnnotationFunction;

Annotation.Root = <S extends StateDefinition>(sd: S) => new AnnotationRoot(sd);

export function getChannel<V, U = V>(
Expand Down
2 changes: 2 additions & 0 deletions libs/langgraph/src/graph/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ import {
import { RunnableCallable } from "../utils.js";
import { InvalidUpdateError } from "../errors.js";

/** Special reserved node name denoting the start of a graph. */
export const START = "__start__";
/** Special reserved node name denoting the end of a graph. */
export const END = "__end__";

export interface BranchOptions<IO, N extends string> {
Expand Down
6 changes: 6 additions & 0 deletions libs/langgraph/src/graph/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ type Messages =
| BaseMessage
| BaseMessageLike;

/**
* Prebuilt reducer that combines returned messages.
* Can handle standard messages and special modifiers like {@link RemoveMessage}
* instances.
*/
export function messagesStateReducer(
left: BaseMessage[],
right: Messages
Expand Down Expand Up @@ -59,6 +64,7 @@ export function messagesStateReducer(
return merged.filter((m) => !idsToRemove.has(m.id));
}

/** @ignore */
export class MessageGraph extends StateGraph<
BaseMessage[],
BaseMessage[],
Expand Down
5 changes: 5 additions & 0 deletions libs/langgraph/src/graph/messages_annotation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import { BaseMessage } from "@langchain/core/messages";
import { Annotation } from "./annotation.js";
import { messagesStateReducer } from "./message.js";

/**
* Prebuilt state annotation that combines returned messages.
* Can handle standard messages and special modifiers like {@link RemoveMessage}
* instances.
*/
export const MessagesAnnotation = Annotation.Root({
messages: Annotation<BaseMessage[]>({
reducer: messagesStateReducer,
Expand Down
62 changes: 62 additions & 0 deletions libs/langgraph/src/graph/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,68 @@ export interface StateGraphArgs<Channels extends object | unknown> {
: ChannelReducers<{ __root__: Channels }>;
}

/**
* A graph whose nodes communicate by reading and writing to a shared state.
* Each node takes a defined `State` as input and returns a `Partial<State>`.
*
* Each state key can optionally be annotated with a reducer function that
* will be used to aggregate the values of that key received from multiple nodes.
* The signature of a reducer function is (left: Value, right: UpdateValue) => Value.
*
* See {@link Annotation} for more on defining state.
*
* After adding nodes and edges to your graph, you must call `.compile()` on it before
* you can use it.
*
* @example
* ```ts
* import {
* type BaseMessage,
* AIMessage,
* HumanMessage,
* } from "@langchain/core/messages";
* import { StateGraph, Annotation } from "@langchain/langgraph";
*
* // Define a state with a single key named "messages" that will
* // combine a returned BaseMessage or arrays of BaseMessages
* const StateAnnotation = Annotation.Root({
* sentiment: Annotation<string>,
* messages: Annotation<BaseMessage[]>({
* reducer: (left: BaseMessage[], right: BaseMessage | BaseMessage[]) => {
* if (Array.isArray(right)) {
* return left.concat(right);
* }
* return left.concat([right]);
* },
* default: () => [],
* }),
* });
*
* const graphBuilder = new StateGraph(StateAnnotation);
*
* // A node in the graph that returns an object with a "messages" key
* // will update the state by combining the existing value with the returned one.
* const myNode = (state: typeof StateAnnotation.State) => {
* return {
* messages: [new AIMessage("Some new response")],
* sentiment: "positive",
* };
* };
*
* const graph = graphBuilder
* .addNode("myNode", myNode)
* .addEdge("__start__", "myNode")
* .addEdge("myNode", "__end__")
* .compile();
*
* await graph.invoke({ messages: [new HumanMessage("how are you?")] });
*
* // {
* // messages: [HumanMessage("how are you?"), AIMessage("Some new response")],
* // sentiment: "positive",
* // }
* ```
*/
export class StateGraph<
SD extends StateDefinition | unknown,
S = SD extends StateDefinition ? StateType<SD> : SD,
Expand Down
2 changes: 2 additions & 0 deletions libs/langgraph/src/prebuilt/agent_executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ interface Step {
observation: unknown;
}

/** @ignore */
export interface AgentExecutorState {
agentOutcome?: AgentAction | AgentFinish;
steps: Array<Step>;
input: string;
chatHistory?: BaseMessage[];
}

/** @ignore */
export function createAgentExecutor({
agentRunnable,
tools,
Expand Down
2 changes: 2 additions & 0 deletions libs/langgraph/src/prebuilt/chat_agent_executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import {
} from "../graph/state.js";
import { END, START } from "../graph/index.js";

/** @ignore */
export type FunctionCallingExecutorState = { messages: Array<BaseMessage> };

/** @ignore */
export function createFunctionCallingExecutor<Model extends object>({
model,
tools,
Expand Down
2 changes: 2 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
},
"include": [
"libs/*/src/**/*",
"libs/*/*.d.ts",
"libs/langgraph/*.d.ts",
"libs/langgraph/*.d.ts",
],
"exclude": [
Expand Down

0 comments on commit 421d255

Please sign in to comment.