@langchain/langgraph
Version:
192 lines (191 loc) • 7.69 kB
JavaScript
const require_constants = require("../constants.cjs");
const require_binop = require("../channels/binop.cjs");
const require_last_value = require("../channels/last_value.cjs");
const require_types = require("./types.cjs");
const require_adapter = require("./adapter.cjs");
const require_delta = require("../channels/delta.cjs");
const require_untracked_value = require("../channels/untracked_value.cjs");
require("../channels/index.cjs");
const require_reduced = require("./values/reduced.cjs");
const require_untracked = require("./values/untracked.cjs");
const require_delta$1 = require("./values/delta.cjs");
//#region src/state/schema.ts
const STATE_SCHEMA_SYMBOL = Symbol.for("langgraph.state.state_schema");
/**
* StateSchema provides a unified API for defining LangGraph state schemas.
*
* @example
* ```ts
* import { z } from "zod";
* import { StateSchema, ReducedValue, MessagesValue } from "@langchain/langgraph";
*
* const AgentState = new StateSchema({
* // Prebuilt messages value
* messages: MessagesValue,
* // Basic LastValue channel from any standard schema
* currentStep: z.string(),
* // LastValue with native default
* count: z.number().default(0),
* // ReducedValue for fields needing reducers
* history: new ReducedValue(
* z.array(z.string()).default(() => []),
* {
* inputSchema: z.string(),
* reducer: (current, next) => [...current, next],
* }
* ),
* });
*
* // Extract types
* type State = typeof AgentState.State;
* type Update = typeof AgentState.Update;
*
* // Use in StateGraph
* const graph = new StateGraph(AgentState);
* ```
*/
var StateSchema = class {
/**
* Symbol for runtime identification.
* @internal Used by isInstance for runtime type checking
*/
[STATE_SCHEMA_SYMBOL] = true;
constructor(fields) {
this.fields = fields;
}
/**
* Get the channel definitions for use with StateGraph.
* This converts the StateSchema fields into BaseChannel instances.
*/
getChannels() {
const channels = {};
for (const [key, value] of Object.entries(this.fields)) if (require_delta$1.DeltaValue.isInstance(value)) {
const defaultGetter = require_adapter.getSchemaDefaultGetter(value.valueSchema);
channels[key] = new require_delta.DeltaChannel(value.reducer, {
snapshotFrequency: value.snapshotFrequency,
initialValueFactory: defaultGetter
});
} else if (require_reduced.ReducedValue.isInstance(value)) {
const defaultGetter = require_adapter.getSchemaDefaultGetter(value.valueSchema);
channels[key] = new require_binop.BinaryOperatorAggregate(value.reducer, defaultGetter);
} else if (require_untracked.UntrackedValue.isInstance(value)) {
const defaultGetter = value.schema ? require_adapter.getSchemaDefaultGetter(value.schema) : void 0;
channels[key] = new require_untracked_value.UntrackedValueChannel({
guard: value.guard,
initialValueFactory: defaultGetter
});
} else if (require_types.isStandardSchema(value)) channels[key] = new require_last_value.LastValue(require_adapter.getSchemaDefaultGetter(value));
else throw new Error(`Invalid state field "${key}": must be a schema, ReducedValue, DeltaValue, UntrackedValue, or ManagedValue`);
return channels;
}
/**
* Get the JSON schema for the full state type.
* Used by Studio and API for schema introspection.
*/
getJsonSchema() {
const properties = {};
const required = [];
for (const [key, value] of Object.entries(this.fields)) {
let fieldSchema;
if (require_delta$1.DeltaValue.isInstance(value) || require_reduced.ReducedValue.isInstance(value)) {
fieldSchema = require_adapter.getJsonSchemaFromSchema(value.valueSchema);
if (value.jsonSchemaExtra) fieldSchema = {
...fieldSchema ?? {},
...value.jsonSchemaExtra
};
} else if (require_untracked.UntrackedValue.isInstance(value)) fieldSchema = value.schema ? require_adapter.getJsonSchemaFromSchema(value.schema) : void 0;
else if (require_types.isStandardSchema(value)) fieldSchema = require_adapter.getJsonSchemaFromSchema(value);
if (fieldSchema) {
properties[key] = fieldSchema;
let hasDefault = false;
if (require_delta$1.DeltaValue.isInstance(value) || require_reduced.ReducedValue.isInstance(value)) hasDefault = require_adapter.getSchemaDefaultGetter(value.valueSchema) !== void 0;
else if (require_untracked.UntrackedValue.isInstance(value)) hasDefault = value.schema ? require_adapter.getSchemaDefaultGetter(value.schema) !== void 0 : false;
else hasDefault = require_adapter.getSchemaDefaultGetter(value) !== void 0;
if (!hasDefault) required.push(key);
}
}
return {
type: "object",
properties,
required: required.length > 0 ? required : void 0
};
}
/**
* Get the JSON schema for the update/input type.
* All fields are optional in updates.
*/
getInputJsonSchema() {
const properties = {};
for (const [key, value] of Object.entries(this.fields)) {
let fieldSchema;
if (require_delta$1.DeltaValue.isInstance(value) || require_reduced.ReducedValue.isInstance(value)) {
fieldSchema = require_adapter.getJsonSchemaFromSchema(value.inputSchema);
if (value.jsonSchemaExtra) fieldSchema = {
...fieldSchema ?? {},
...value.jsonSchemaExtra
};
} else if (require_untracked.UntrackedValue.isInstance(value)) fieldSchema = value.schema ? require_adapter.getJsonSchemaFromSchema(value.schema) : void 0;
else if (require_types.isStandardSchema(value)) fieldSchema = require_adapter.getJsonSchemaFromSchema(value);
if (fieldSchema) properties[key] = fieldSchema;
}
return {
type: "object",
properties
};
}
/**
* Get the list of channel keys (excluding managed values).
*/
getChannelKeys() {
return Object.entries(this.fields).map(([key]) => key);
}
/**
* Get all keys (channels + managed values).
*/
getAllKeys() {
return Object.keys(this.fields);
}
/**
* Validate input data against the schema.
* This validates each field using its corresponding schema.
*
* @param data - The input data to validate
* @returns The validated data with coerced types
*/
async validateInput(data) {
if (data == null || typeof data !== "object") return data;
const result = {};
for (const [key, value] of Object.entries(data)) {
const fieldDef = this.fields[key];
if (fieldDef === void 0) {
result[key] = value;
continue;
}
let schema;
if (require_delta$1.DeltaValue.isInstance(fieldDef) || require_reduced.ReducedValue.isInstance(fieldDef)) {
const [isOverwrite, overwriteValue] = require_constants._getOverwriteValue(value);
if (isOverwrite) {
schema = fieldDef.valueSchema;
const validationResult = await schema["~standard"].validate(overwriteValue);
if (validationResult.issues) throw new Error(`Validation failed for field "${key}": ${JSON.stringify(validationResult.issues)}`);
result[key] = { [require_constants.OVERWRITE]: validationResult.value };
continue;
}
schema = fieldDef.inputSchema;
} else if (require_untracked.UntrackedValue.isInstance(fieldDef)) schema = fieldDef.schema;
else if (require_types.isStandardSchema(fieldDef)) schema = fieldDef;
if (schema) {
const validationResult = await schema["~standard"].validate(value);
if (validationResult.issues) throw new Error(`Validation failed for field "${key}": ${JSON.stringify(validationResult.issues)}`);
result[key] = validationResult.value;
} else result[key] = value;
}
return result;
}
static isInstance(value) {
return typeof value === "object" && value !== null && STATE_SCHEMA_SYMBOL in value && value[STATE_SCHEMA_SYMBOL] === true;
}
};
//#endregion
exports.StateSchema = StateSchema;
//# sourceMappingURL=schema.cjs.map