feat: add shadow LangGraph orchestrator runtime
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import { MemorySaver } from '@langchain/langgraph';
|
||||
import { PostgresSaver } from '@langchain/langgraph-checkpoint-postgres';
|
||||
|
||||
const DEFAULT_POSTGRES_SCHEMA = 'memind_orchestrator';
|
||||
|
||||
function normalizeMode(value) {
|
||||
const mode = String(value ?? 'postgres').trim().toLowerCase();
|
||||
if (mode === 'memory' || mode === 'postgres') return mode;
|
||||
throw new Error(`Unsupported orchestrator checkpoint mode: ${value}`);
|
||||
}
|
||||
|
||||
function normalizeSchema(value) {
|
||||
const schema = String(value ?? DEFAULT_POSTGRES_SCHEMA).trim();
|
||||
if (!/^[a-z_][a-z0-9_]{0,62}$/i.test(schema)) {
|
||||
throw new Error('Invalid orchestrator PostgreSQL schema');
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
export async function createOrchestratorCheckpoint({
|
||||
mode = process.env.MEMIND_ORCHESTRATOR_CHECKPOINT_MODE,
|
||||
connectionString = process.env.MEMIND_ORCHESTRATOR_DATABASE_URL,
|
||||
schema = process.env.MEMIND_ORCHESTRATOR_DATABASE_SCHEMA,
|
||||
} = {}) {
|
||||
const normalizedMode = normalizeMode(mode);
|
||||
if (normalizedMode === 'memory') {
|
||||
return {
|
||||
kind: 'memory',
|
||||
durable: false,
|
||||
checkpointer: new MemorySaver(),
|
||||
async probe() {
|
||||
return true;
|
||||
},
|
||||
async close() {},
|
||||
};
|
||||
}
|
||||
|
||||
const normalizedConnectionString = String(connectionString ?? '').trim();
|
||||
if (!normalizedConnectionString) {
|
||||
const error = new Error(
|
||||
'MEMIND_ORCHESTRATOR_DATABASE_URL is required when checkpoint mode is postgres',
|
||||
);
|
||||
error.code = 'ORCHESTRATOR_DATABASE_URL_REQUIRED';
|
||||
throw error;
|
||||
}
|
||||
|
||||
const checkpointer = PostgresSaver.fromConnString(normalizedConnectionString, {
|
||||
schema: normalizeSchema(schema),
|
||||
});
|
||||
await checkpointer.setup();
|
||||
return {
|
||||
kind: 'postgres',
|
||||
durable: true,
|
||||
checkpointer,
|
||||
async probe() {
|
||||
await checkpointer.getTuple({
|
||||
configurable: {
|
||||
thread_id: '__orchestrator_readiness__',
|
||||
checkpoint_ns: '',
|
||||
},
|
||||
});
|
||||
return true;
|
||||
},
|
||||
async close() {
|
||||
await checkpointer.end();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const orchestratorCheckpointInternals = {
|
||||
DEFAULT_POSTGRES_SCHEMA,
|
||||
normalizeMode,
|
||||
normalizeSchema,
|
||||
};
|
||||
Reference in New Issue
Block a user