@skein-js/server-kit 0.6.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -0
- package/dist/index.d.ts +51 -3
- package/dist/index.js +52 -18
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -19,6 +19,10 @@ handler table.
|
|
|
19
19
|
- **In-memory dev runtime** — `loadInMemoryRuntime` / `loadReloadableInMemoryRuntime`: assemble a
|
|
20
20
|
`ProtocolDeps` backed by in-process drivers from a `langgraph.json`. This is what powers `skein dev`
|
|
21
21
|
and every adapter's `{ config }` convenience path (hot-reload + snapshot/restore included).
|
|
22
|
+
- **In-code embedding** — `embedInMemoryGraphs` / `graphMapToResolver`: build a `ProtocolDeps` around a
|
|
23
|
+
compiled graph (or map of them) you already hold — **no `langgraph.json`, no CLI** — then pass
|
|
24
|
+
`{ deps }` to any adapter. `overrides` swaps in production drivers/auth. See
|
|
25
|
+
[docs/embedding.md](../../docs/embedding.md).
|
|
22
26
|
- **LangGraph dev-state import** — `readLanggraphDevState` / `loadSnapshotIntoStore` /
|
|
23
27
|
`describeSnapshot`: read an existing `.langgraph_api/` directory and reconstruct skein's own
|
|
24
28
|
`DevStateSnapshot`, so adopting skein carries all local state over losslessly.
|
|
@@ -33,6 +37,55 @@ handler table.
|
|
|
33
37
|
> [`@skein-js/agent-protocol`](../agent-protocol), since it references the handler names. Adapters
|
|
34
38
|
> import it from there.
|
|
35
39
|
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pnpm add @skein-js/server-kit @langchain/langgraph
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`@langchain/langgraph` is a peer dependency. You install this package directly when you **embed a
|
|
47
|
+
graph in code** (`embedInMemoryGraphs`) or **write your own adapter**; the shipped adapters depend on
|
|
48
|
+
it for you.
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
The most common direct use is the in-code on-ramp — turn a compiled graph (or a map of them) into a
|
|
53
|
+
`ProtocolDeps` and hand `{ deps }` to any adapter, with **no `langgraph.json` and no CLI**:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { createExpressServer } from "@skein-js/express";
|
|
57
|
+
import { embedInMemoryGraphs } from "@skein-js/server-kit";
|
|
58
|
+
import { graph } from "./my-graph.js";
|
|
59
|
+
|
|
60
|
+
const server = await createExpressServer({ deps: embedInMemoryGraphs({ agent: graph }) });
|
|
61
|
+
await server.listen(2024);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Pass `overrides` to swap in production drivers or an auth engine while keeping the rest in-memory. See
|
|
65
|
+
[docs/embedding.md](../../docs/embedding.md).
|
|
66
|
+
|
|
67
|
+
## API
|
|
68
|
+
|
|
69
|
+
- **`embedInMemoryGraphs(graphs, options?): ProtocolDeps`** — build a `ProtocolDeps` (store, queue,
|
|
70
|
+
bus, checkpointer) around a compiled graph or `Record<string, EmbeddableGraph>`. `options.overrides`
|
|
71
|
+
replaces any dep (e.g. a Postgres store, an `auth` engine). `createInMemoryDeps` is a
|
|
72
|
+
**`@deprecated`** alias. `graphMapToResolver` / `normalizeEmbeddableGraphs` are the lower-level
|
|
73
|
+
graph→`GraphResolver` helpers.
|
|
74
|
+
- **`resolveProtocolRuntime(options): Promise<ResolvedProtocolRuntime>`** — turn a
|
|
75
|
+
`{ config } | { deps }` bag (`SkeinRuntimeOptions`) into a live runtime (assistants seeded, worker
|
|
76
|
+
started) — the step every adapter runs before mounting routes.
|
|
77
|
+
- **`loadInMemoryRuntime` / `loadReloadableInMemoryRuntime`** — assemble a `ProtocolDeps` from a
|
|
78
|
+
`langgraph.json` using in-process drivers. The reloadable variant adds `reloadGraphs` /
|
|
79
|
+
`snapshotState` / `hydrateState` (what powers `skein dev`'s hot reload + cross-restart persistence).
|
|
80
|
+
- **`readLanggraphDevState` / `loadSnapshotIntoStore` / `describeSnapshot`** — read an existing
|
|
81
|
+
`.langgraph_api/` directory and reconstruct a `DevStateSnapshot`, so adopting skein carries local
|
|
82
|
+
state over losslessly.
|
|
83
|
+
- **CORS** — `corsFromHttpConfig` / `toCorsOptions` map a `langgraph.json` `http.cors` block to
|
|
84
|
+
`cors`-style options; `allowedOrigin` / `corsResponseHeaders` / `applyNodeCors` / `sendNodePreflight`
|
|
85
|
+
derive CORS headers for adapters without a CORS middleware of their own.
|
|
86
|
+
- **Node transport** — `sendNodeResponse` / `sendNodeError` serialize a `ProtocolResponse`
|
|
87
|
+
(JSON / 204 / SSE) onto a Node `ServerResponse`, shared by the NestJS + Next.js Pages Router adapters.
|
|
88
|
+
|
|
36
89
|
## Learn more
|
|
37
90
|
|
|
38
91
|
- [Building your own adapter](../../docs/building-an-adapter.md)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { ProtocolRuntime, Logger, ProtocolDeps, ProtocolResponse } from '@skein-js/agent-protocol';
|
|
1
|
+
import { ProtocolRuntime, Logger, ProtocolDeps, GraphResolver, ProtocolResponse } from '@skein-js/agent-protocol';
|
|
2
|
+
export { CompiledGraphFactory, GraphResolver, ProtocolDeps, ResolvedGraph } from '@skein-js/agent-protocol';
|
|
2
3
|
import { ModuleImporter, GraphSchemas } from '@skein-js/config';
|
|
3
4
|
import { CorsOptions } from 'cors';
|
|
4
5
|
export { CorsOptions } from 'cors';
|
|
5
6
|
import { MemoryStoreSnapshot } from '@skein-js/storage-memory';
|
|
6
|
-
import { BaseCheckpointSaver } from '@langchain/langgraph';
|
|
7
|
+
import { CompiledGraph, BaseCheckpointSaver } from '@langchain/langgraph';
|
|
7
8
|
import { SkeinStore } from '@skein-js/core';
|
|
8
9
|
import { ServerResponse } from 'node:http';
|
|
9
10
|
|
|
@@ -97,6 +98,53 @@ interface ReloadableInMemoryRuntime extends InMemoryRuntimeConfig {
|
|
|
97
98
|
*/
|
|
98
99
|
declare function loadReloadableInMemoryRuntime(configPath: string, importModule?: ModuleImporter, staticSchemas?: Record<string, GraphSchemas>): Promise<ReloadableInMemoryRuntime>;
|
|
99
100
|
|
|
101
|
+
type AnyCompiledGraph = CompiledGraph<any>;
|
|
102
|
+
/**
|
|
103
|
+
* A graph you can embed in code: any compiled LangGraph.js graph, or a factory that builds one per run
|
|
104
|
+
* (called with the run's `configurable`). Keys of a graph map become graph ids.
|
|
105
|
+
*/
|
|
106
|
+
type EmbeddableGraph = AnyCompiledGraph | ((config: {
|
|
107
|
+
configurable?: Record<string, unknown>;
|
|
108
|
+
}) => AnyCompiledGraph | Promise<AnyCompiledGraph>);
|
|
109
|
+
/**
|
|
110
|
+
* Accept either a ready {@link GraphResolver} or a plain graph map and return a `GraphResolver` either
|
|
111
|
+
* way — the normalization every in-code embedding helper shares (`embedInMemoryGraphs` here,
|
|
112
|
+
* `embedPostgresGraphs` in `@skein-js/runtime`), so the {@link isGraphResolver} discriminator lives in
|
|
113
|
+
* exactly one place.
|
|
114
|
+
*/
|
|
115
|
+
declare function normalizeEmbeddableGraphs(graphs: GraphResolver | Record<string, EmbeddableGraph>): GraphResolver;
|
|
116
|
+
/**
|
|
117
|
+
* Turn a map of compiled graphs (or per-config factories) into a {@link GraphResolver}. Keys become the
|
|
118
|
+
* graph ids — one auto-registered assistant each. `schemas()` returns a minimal `{ graph_id }` stub:
|
|
119
|
+
* enough for the assistants introspection endpoints and everything `useStream` / Agent Chat UI render.
|
|
120
|
+
* Real input/output/state schema extraction stays a `langgraph.json`/config feature — it needs static
|
|
121
|
+
* TypeScript analysis of the graph source, which a compiled graph object no longer carries.
|
|
122
|
+
*/
|
|
123
|
+
declare function graphMapToResolver(graphs: Record<string, EmbeddableGraph>): GraphResolver;
|
|
124
|
+
/**
|
|
125
|
+
* Build a `ProtocolDeps` backed by fresh in-process drivers (store, queue, bus, checkpointer) around
|
|
126
|
+
* graphs you already hold in code — no `langgraph.json`, no CLI. Pass a map of compiled graphs (or
|
|
127
|
+
* factories), or a ready {@link GraphResolver}. Hand the result to any adapter's `{ deps }` seam:
|
|
128
|
+
*
|
|
129
|
+
* ```ts
|
|
130
|
+
* import { embedInMemoryGraphs } from "@skein-js/server-kit";
|
|
131
|
+
* import { createExpressServer } from "@skein-js/express";
|
|
132
|
+
*
|
|
133
|
+
* createExpressServer({ deps: embedInMemoryGraphs({ myAgent: graph }) }).listen(2024);
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* `overrides` replaces any driver or adds `auth`/`logger` — e.g. swap in a Postgres store + Redis
|
|
137
|
+
* queue for a durable, horizontally-scalable deployment. `graphs` is intentionally excluded from
|
|
138
|
+
* `overrides` (the first argument is the single source of graphs), so a stray `graphs` key can't
|
|
139
|
+
* silently void it.
|
|
140
|
+
*/
|
|
141
|
+
declare function embedInMemoryGraphs(graphs: GraphResolver | Record<string, EmbeddableGraph>, overrides?: Omit<Partial<ProtocolDeps>, "graphs">): ProtocolDeps;
|
|
142
|
+
/**
|
|
143
|
+
* @deprecated Renamed to {@link embedInMemoryGraphs} — the function takes graphs and returns a
|
|
144
|
+
* `ProtocolDeps`, not a graph. Kept for back-compat; slated for removal in a future major.
|
|
145
|
+
*/
|
|
146
|
+
declare const createInMemoryDeps: typeof embedInMemoryGraphs;
|
|
147
|
+
|
|
100
148
|
/**
|
|
101
149
|
* Read a LangGraph `.langgraph_api/` directory and reconstruct skein's `DevStateSnapshot`.
|
|
102
150
|
* Returns `null` when the directory holds none of the expected files (nothing to import).
|
|
@@ -166,4 +214,4 @@ declare function sendNodeResponse(response: ProtocolResponse, res: ServerRespons
|
|
|
166
214
|
/** Serialize a caught error onto the Node `res`, using the protocol status when the error carries one. */
|
|
167
215
|
declare function sendNodeError(error: unknown, res: ServerResponse, logger?: Logger, adapterName?: string): void;
|
|
168
216
|
|
|
169
|
-
export { type CorsSetting, type DevStateCounts, type DevStateSnapshot, type InMemoryRuntimeConfig, type LanggraphCorsConfig, type ReloadableInMemoryRuntime, type ResolvedProtocolRuntime, type SkeinRuntimeCommonOptions, type SkeinRuntimeOptions, allowedOrigin, applyNodeCors, corsFromHttpConfig, corsPreflightHeaders, corsResponseHeaders, describeSnapshot, joinList, loadInMemoryRuntime, loadReloadableInMemoryRuntime, loadSnapshotIntoStore, readLanggraphDevState, resolveProtocolRuntime, sendNodeError, sendNodePreflight, sendNodeResponse, toCorsOptions };
|
|
217
|
+
export { type CorsSetting, type DevStateCounts, type DevStateSnapshot, type EmbeddableGraph, type InMemoryRuntimeConfig, type LanggraphCorsConfig, type ReloadableInMemoryRuntime, type ResolvedProtocolRuntime, type SkeinRuntimeCommonOptions, type SkeinRuntimeOptions, allowedOrigin, applyNodeCors, corsFromHttpConfig, corsPreflightHeaders, corsResponseHeaders, createInMemoryDeps, describeSnapshot, embedInMemoryGraphs, graphMapToResolver, joinList, loadInMemoryRuntime, loadReloadableInMemoryRuntime, loadSnapshotIntoStore, normalizeEmbeddableGraphs, readLanggraphDevState, resolveProtocolRuntime, sendNodeError, sendNodePreflight, sendNodeResponse, toCorsOptions };
|
package/dist/index.js
CHANGED
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
} from "@skein-js/agent-protocol";
|
|
5
5
|
|
|
6
6
|
// src/in-memory-runtime.ts
|
|
7
|
-
import { MemorySaver } from "@langchain/langgraph";
|
|
7
|
+
import { MemorySaver as MemorySaver2 } from "@langchain/langgraph";
|
|
8
8
|
import {
|
|
9
9
|
loadAuthEngine,
|
|
10
10
|
loadConfig
|
|
11
11
|
} from "@skein-js/config";
|
|
12
|
-
import { MemoryRunEventBus, MemoryRunQueue, MemorySkeinStore } from "@skein-js/storage-memory";
|
|
12
|
+
import { MemoryRunEventBus as MemoryRunEventBus2, MemoryRunQueue as MemoryRunQueue2, MemorySkeinStore as MemorySkeinStore2 } from "@skein-js/storage-memory";
|
|
13
13
|
|
|
14
14
|
// src/cors-config.ts
|
|
15
15
|
var ALWAYS_EXPOSED_HEADERS = ["content-location", "x-pagination-total"];
|
|
@@ -93,21 +93,51 @@ function hydrateCheckpointer(saver, snapshot) {
|
|
|
93
93
|
);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
// src/in-memory-
|
|
97
|
-
|
|
96
|
+
// src/in-memory-deps.ts
|
|
97
|
+
import { MemorySaver } from "@langchain/langgraph";
|
|
98
|
+
import { MemoryRunEventBus, MemoryRunQueue, MemorySkeinStore } from "@skein-js/storage-memory";
|
|
99
|
+
function isGraphResolver(graphs) {
|
|
100
|
+
const candidate = graphs;
|
|
101
|
+
return Array.isArray(candidate.ids) && typeof candidate.load === "function";
|
|
102
|
+
}
|
|
103
|
+
function normalizeEmbeddableGraphs(graphs) {
|
|
104
|
+
return isGraphResolver(graphs) ? graphs : graphMapToResolver(graphs);
|
|
105
|
+
}
|
|
106
|
+
function graphMapToResolver(graphs) {
|
|
107
|
+
const ids = Object.keys(graphs);
|
|
98
108
|
return {
|
|
99
|
-
ids
|
|
100
|
-
load: (graphId) =>
|
|
101
|
-
|
|
109
|
+
ids,
|
|
110
|
+
load: async (graphId) => {
|
|
111
|
+
const graph = graphs[graphId];
|
|
112
|
+
if (graph == null) {
|
|
113
|
+
const known = ids.join(", ") || "none";
|
|
114
|
+
throw new Error(
|
|
115
|
+
ids.includes(graphId) ? `Graph "${graphId}" resolved to ${String(graph)} \u2014 check its export/factory (known: ${known}).` : `Unknown graph "${graphId}" (known: ${known}).`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
return graph;
|
|
119
|
+
},
|
|
120
|
+
schemas: async (graphId) => ({ [graphId]: { graph_id: graphId } })
|
|
102
121
|
};
|
|
103
122
|
}
|
|
104
|
-
function
|
|
123
|
+
function embedInMemoryGraphs(graphs, overrides = {}) {
|
|
105
124
|
return {
|
|
106
125
|
store: new MemorySkeinStore(),
|
|
107
|
-
graphs,
|
|
126
|
+
graphs: normalizeEmbeddableGraphs(graphs),
|
|
108
127
|
queue: new MemoryRunQueue(),
|
|
109
128
|
bus: new MemoryRunEventBus(),
|
|
110
|
-
checkpointer: new MemorySaver()
|
|
129
|
+
checkpointer: new MemorySaver(),
|
|
130
|
+
...overrides
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
var createInMemoryDeps = embedInMemoryGraphs;
|
|
134
|
+
|
|
135
|
+
// src/in-memory-runtime.ts
|
|
136
|
+
function toGraphResolver(graphs) {
|
|
137
|
+
return {
|
|
138
|
+
ids: graphs.ids,
|
|
139
|
+
load: (graphId) => graphs.load(graphId),
|
|
140
|
+
schemas: async (graphId) => await graphs.schemas(graphId)
|
|
111
141
|
};
|
|
112
142
|
}
|
|
113
143
|
async function loadInMemoryRuntime(configPath, importModule, staticSchemas) {
|
|
@@ -116,7 +146,7 @@ async function loadInMemoryRuntime(configPath, importModule, staticSchemas) {
|
|
|
116
146
|
importModule,
|
|
117
147
|
staticSchemas
|
|
118
148
|
});
|
|
119
|
-
const deps =
|
|
149
|
+
const deps = embedInMemoryGraphs(toGraphResolver(graphs));
|
|
120
150
|
deps.auth = await loadAuthEngine(config.auth, { configDir, importModule });
|
|
121
151
|
return {
|
|
122
152
|
deps,
|
|
@@ -131,13 +161,13 @@ async function loadReloadableInMemoryRuntime(configPath, importModule, staticSch
|
|
|
131
161
|
load: (graphId) => current.load(graphId),
|
|
132
162
|
schemas: async (graphId) => await current.schemas(graphId)
|
|
133
163
|
};
|
|
134
|
-
const store = new
|
|
135
|
-
const checkpointer = new
|
|
164
|
+
const store = new MemorySkeinStore2();
|
|
165
|
+
const checkpointer = new MemorySaver2();
|
|
136
166
|
const deps = {
|
|
137
167
|
store,
|
|
138
168
|
graphs,
|
|
139
|
-
queue: new
|
|
140
|
-
bus: new
|
|
169
|
+
queue: new MemoryRunQueue2(),
|
|
170
|
+
bus: new MemoryRunEventBus2(),
|
|
141
171
|
checkpointer,
|
|
142
172
|
auth: await loadAuthEngine(first.config.auth, { configDir: first.configDir, importModule })
|
|
143
173
|
};
|
|
@@ -189,7 +219,7 @@ async function resolveProtocolRuntime(options) {
|
|
|
189
219
|
import { readFile } from "fs/promises";
|
|
190
220
|
import path from "path";
|
|
191
221
|
import {
|
|
192
|
-
MemorySaver as
|
|
222
|
+
MemorySaver as MemorySaver3
|
|
193
223
|
} from "@langchain/langgraph";
|
|
194
224
|
import {
|
|
195
225
|
isTerminalRunStatus
|
|
@@ -417,7 +447,7 @@ async function readLanggraphDevState(langgraphApiDir) {
|
|
|
417
447
|
};
|
|
418
448
|
let checkpoints = { storage: {}, writes: {} };
|
|
419
449
|
if (checkpointerFile) {
|
|
420
|
-
const saver = new
|
|
450
|
+
const saver = new MemorySaver3();
|
|
421
451
|
saver.storage = checkpointerFile.storage;
|
|
422
452
|
saver.writes = checkpointerFile.writes;
|
|
423
453
|
checkpoints = snapshotCheckpointer(saver);
|
|
@@ -437,7 +467,7 @@ function supportsRestore(store) {
|
|
|
437
467
|
return typeof store.restore === "function";
|
|
438
468
|
}
|
|
439
469
|
async function copyCheckpoints(snapshot, target) {
|
|
440
|
-
const source = new
|
|
470
|
+
const source = new MemorySaver3();
|
|
441
471
|
hydrateCheckpointer(source, snapshot);
|
|
442
472
|
const tuples = [];
|
|
443
473
|
for await (const tuple of source.list({})) tuples.push(tuple);
|
|
@@ -615,11 +645,15 @@ export {
|
|
|
615
645
|
corsFromHttpConfig,
|
|
616
646
|
corsPreflightHeaders,
|
|
617
647
|
corsResponseHeaders,
|
|
648
|
+
createInMemoryDeps,
|
|
618
649
|
describeSnapshot,
|
|
650
|
+
embedInMemoryGraphs,
|
|
651
|
+
graphMapToResolver,
|
|
619
652
|
joinList,
|
|
620
653
|
loadInMemoryRuntime,
|
|
621
654
|
loadReloadableInMemoryRuntime,
|
|
622
655
|
loadSnapshotIntoStore,
|
|
656
|
+
normalizeEmbeddableGraphs,
|
|
623
657
|
readLanggraphDevState,
|
|
624
658
|
resolveProtocolRuntime,
|
|
625
659
|
sendNodeError,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skein-js/server-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Shared, framework-agnostic building blocks for skein-js HTTP adapters — in-memory dev runtime, LangGraph dev-state import, and langgraph.json CORS mapping.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Maina Wycliffe <wmmaina7@gmail.com>",
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
"cors": "^2.8.5",
|
|
44
44
|
"superjson": "^2.2.6",
|
|
45
45
|
"zod": "^3.25.76",
|
|
46
|
-
"@skein-js/
|
|
47
|
-
"@skein-js/config": "0.
|
|
48
|
-
"@skein-js/
|
|
49
|
-
"@skein-js/storage-memory": "0.
|
|
46
|
+
"@skein-js/core": "0.8.0",
|
|
47
|
+
"@skein-js/config": "0.8.0",
|
|
48
|
+
"@skein-js/agent-protocol": "0.8.0",
|
|
49
|
+
"@skein-js/storage-memory": "0.8.0"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"@langchain/langgraph": "^1.4.0"
|