@skein-js/server-kit 0.10.0 → 0.11.2
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 +11 -2
- package/dist/index.d.ts +99 -8
- package/dist/index.js +137 -11
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -34,6 +34,10 @@ handler table.
|
|
|
34
34
|
/ SSE) onto a Node `ServerResponse`, shared by the NestJS + Next.js Pages Router adapters.
|
|
35
35
|
- **Mount prefix** — `stripBasePath`: strip the path an adapter is mounted under before matching the
|
|
36
36
|
route table, for adapters that mount a catch-all and match by hand (NestJS, Next.js).
|
|
37
|
+
- **Logging** — `createConsoleLogger`: the opt-in `Logger` for adapters whose framework owns none
|
|
38
|
+
(Express, Next.js). `formatLogMeta` / `describeError` are the shared rendering every line-oriented
|
|
39
|
+
logger needs — a failed run's identity, stack, and `cause` chain — so the framework bridges and the
|
|
40
|
+
CLI's dev logger can't drift on how a failure reads.
|
|
37
41
|
|
|
38
42
|
> The route table itself (`skeinRoutes`) is **not** here — it lives with the engine in
|
|
39
43
|
> [`@skein-js/agent-protocol`](../agent-protocol), since it references the handler names. Adapters
|
|
@@ -73,11 +77,16 @@ Pass `overrides` to swap in production drivers or an auth engine while keeping t
|
|
|
73
77
|
replaces any dep (e.g. a Postgres store, an `auth` engine). `createInMemoryDeps` is a
|
|
74
78
|
**`@deprecated`** alias. `graphMapToResolver` / `normalizeEmbeddableGraphs` are the lower-level
|
|
75
79
|
graph→`GraphResolver` helpers.
|
|
76
|
-
- **`resolveProtocolRuntime(options): Promise<ResolvedProtocolRuntime>`** — turn a
|
|
80
|
+
- **`resolveProtocolRuntime(options, frameworkLogger?): Promise<ResolvedProtocolRuntime>`** — turn a
|
|
77
81
|
`{ config } | { deps }` bag (`SkeinRuntimeOptions`) into a live runtime (assistants seeded, worker
|
|
78
82
|
started) — the step every adapter runs before mounting routes. `options.worker`
|
|
79
83
|
(`RunWorkerOptions`) tunes the background worker; `worker.maxConcurrency` is how many queued runs
|
|
80
|
-
run at once.
|
|
84
|
+
run at once. `frameworkLogger` is the adapter's own default, applied only when the caller supplied
|
|
85
|
+
neither `options.logger` nor `deps.logger`; the result's `.logger` is the winner, which the adapter
|
|
86
|
+
should also use for its transport-fault logging.
|
|
87
|
+
- **`createConsoleLogger(options?): Logger`** — a plain `console.*` logger (`level`, `prefix`), for
|
|
88
|
+
adapters whose framework owns none. `formatLogMeta(meta)` / `describeError(thrown)` render a failed
|
|
89
|
+
run's identity, stack, and `cause` chain as text.
|
|
81
90
|
- **`resolveRunConcurrency(explicit?, env?): number`** — the one precedence chain behind
|
|
82
91
|
`worker.maxConcurrency`: explicit value → `SKEIN_RUN_CONCURRENCY` → `N_JOBS_PER_WORKER` →
|
|
83
92
|
`DEFAULT_RUN_CONCURRENCY` (10, matching the LangGraph CLI). The environment is validated even when
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ProtocolRuntime,
|
|
2
|
-
export { CompiledGraphFactory, DEFAULT_RUN_CONCURRENCY, DEFAULT_SHUTDOWN_GRACE_MS, GraphResolver, ProtocolDeps, ResolvedGraph, RunWorkerOptions } from '@skein-js/agent-protocol';
|
|
3
|
-
import { ModuleImporter, GraphSchemas } from '@skein-js/config';
|
|
1
|
+
import { ProtocolRuntime, Logger, ProtocolDeps, RunWorkerOptions, RunFailureReport, GraphResolver, ProtocolResponse } from '@skein-js/agent-protocol';
|
|
2
|
+
export { CompiledGraphFactory, DEFAULT_RUN_CONCURRENCY, DEFAULT_SHUTDOWN_GRACE_MS, GraphResolver, Logger, ProtocolDeps, ResolvedGraph, RunWorkerOptions } from '@skein-js/agent-protocol';
|
|
3
|
+
import { ModuleImporter, LanggraphJson, GraphSchemas } from '@skein-js/config';
|
|
4
4
|
import { CorsOptions } from 'cors';
|
|
5
5
|
export { CorsOptions } from 'cors';
|
|
6
6
|
import { MemoryStoreSnapshot } from '@skein-js/storage-memory';
|
|
@@ -9,7 +9,25 @@ import { SkeinStore } from '@skein-js/core';
|
|
|
9
9
|
import { ServerResponse } from 'node:http';
|
|
10
10
|
|
|
11
11
|
interface SkeinRuntimeCommonOptions {
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Where skein reports itself: failed runs, webhook delivery failures, background-run summaries, and
|
|
14
|
+
* the adapter's own transport faults. It reaches **the run engine**, not just the transport — this
|
|
15
|
+
* is the one knob that decides whether a crashed graph is visible at all.
|
|
16
|
+
*
|
|
17
|
+
* Precedence, most explicit first:
|
|
18
|
+
*
|
|
19
|
+
* | You pass | Result |
|
|
20
|
+
* | ------------------------ | ----------------------------------------------------------------- |
|
|
21
|
+
* | a `Logger` | that logger, overriding any `deps.logger` |
|
|
22
|
+
* | `false` | the adapter contributes nothing and installs no default; an injected `deps.logger` still stands |
|
|
23
|
+
* | nothing | `deps.logger` if you injected one, else the adapter's framework default |
|
|
24
|
+
*
|
|
25
|
+
* The framework default exists only where the framework owns a logger the host has already
|
|
26
|
+
* configured: NestJS (`@nestjs/common`'s `Logger`, honoring `app.useLogger()`) and Fastify
|
|
27
|
+
* (`fastify.log`). Express and Next.js own no such thing, so they stay silent unless you pass one —
|
|
28
|
+
* `createConsoleLogger()` is the one-liner.
|
|
29
|
+
*/
|
|
30
|
+
logger?: Logger | false;
|
|
13
31
|
/**
|
|
14
32
|
* Cross-origin access for browser clients (Agent Chat UI, React `useStream`). When omitted, CORS is
|
|
15
33
|
* driven by the config's `http.cors` block (LangGraph-compatible) and is otherwise **off** — we do
|
|
@@ -60,12 +78,21 @@ interface ResolvedProtocolRuntime {
|
|
|
60
78
|
runtime: ProtocolRuntime;
|
|
61
79
|
/** CORS mapped from the config's `http.cors`, or `undefined` for the injected-`deps` path. */
|
|
62
80
|
cors?: CorsOptions;
|
|
81
|
+
/**
|
|
82
|
+
* The logger the engine ended up with, after {@link SkeinRuntimeCommonOptions.logger}'s precedence
|
|
83
|
+
* chain. `undefined` means nothing logs. Adapters read this (rather than `options.logger`) for
|
|
84
|
+
* their own transport-fault logging, so the engine and the transport can never disagree about
|
|
85
|
+
* where output goes.
|
|
86
|
+
*/
|
|
87
|
+
logger?: Logger;
|
|
63
88
|
}
|
|
64
89
|
/** Just the dependencies behind a `{ config } | { deps }` bag — no runtime, no worker. */
|
|
65
90
|
interface ResolvedRuntimeDeps {
|
|
66
91
|
deps: ProtocolDeps;
|
|
67
92
|
/** CORS mapped from the config's `http.cors`, or `undefined` for the injected-`deps` path. */
|
|
68
93
|
cors?: CorsOptions;
|
|
94
|
+
/** The resolved logger — see {@link ResolvedProtocolRuntime.logger}. */
|
|
95
|
+
logger?: Logger;
|
|
69
96
|
}
|
|
70
97
|
/**
|
|
71
98
|
* Resolve the `{ config } | { deps }` seam down to a `ProtocolDeps` — injected as-is, or fresh
|
|
@@ -73,15 +100,65 @@ interface ResolvedRuntimeDeps {
|
|
|
73
100
|
* {@link resolveProtocolRuntime} that stops short of building the engine, so the simplified invoke
|
|
74
101
|
* surface (which needs only graphs + store) doesn't seed assistants or start a run worker it will
|
|
75
102
|
* never use.
|
|
103
|
+
*
|
|
104
|
+
* `frameworkLogger` is the adapter's own default (Nest's `Logger`, `fastify.log`), used only when the
|
|
105
|
+
* caller supplied neither `options.logger` nor `deps.logger`.
|
|
76
106
|
*/
|
|
77
|
-
declare function resolveRuntimeDeps(options: SkeinRuntimeOptions): Promise<ResolvedRuntimeDeps>;
|
|
107
|
+
declare function resolveRuntimeDeps(options: SkeinRuntimeOptions, frameworkLogger?: Logger): Promise<ResolvedRuntimeDeps>;
|
|
78
108
|
/**
|
|
79
109
|
* Build a `ProtocolRuntime` from adapter options: resolve `deps` (injected, or fresh in-memory
|
|
80
110
|
* drivers from a `langgraph.json`), seed one assistant per declared graph, optionally warm the
|
|
81
111
|
* graphs, and start the background run worker. Returns the runtime plus any CORS derived from the
|
|
82
112
|
* config so the adapter can apply it. The caller owns shutdown (`runtime.worker.stop()`).
|
|
113
|
+
*
|
|
114
|
+
* `frameworkLogger` is the adapter's own default — see {@link resolveRuntimeDeps}.
|
|
115
|
+
*/
|
|
116
|
+
declare function resolveProtocolRuntime(options: SkeinRuntimeOptions, frameworkLogger?: Logger): Promise<ResolvedProtocolRuntime>;
|
|
117
|
+
|
|
118
|
+
/** Levels in ascending severity — the order `level` filters against. */
|
|
119
|
+
declare const LEVELS: readonly ["debug", "info", "warn", "error"];
|
|
120
|
+
type ConsoleLogLevel = (typeof LEVELS)[number];
|
|
121
|
+
interface ConsoleLoggerOptions {
|
|
122
|
+
/**
|
|
123
|
+
* Quietest level to emit; anything below it is dropped. Defaults to `"info"`, which covers failed
|
|
124
|
+
* runs, webhook/rollback problems, and the one-line background-run summaries, while leaving
|
|
125
|
+
* `debug` off. `"warn"` suppresses the per-run summaries but never hides a failure.
|
|
126
|
+
*/
|
|
127
|
+
level?: ConsoleLogLevel;
|
|
128
|
+
/** Prefix on every line, identifying the output as skein's. Defaults to `"skein"`. */
|
|
129
|
+
prefix?: string;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* A plain console `Logger`. Pass it as an adapter's `logger` to see what skein reports — failed
|
|
133
|
+
* runs (with the stack and `cause` chain), webhook delivery failures, and background-run summaries:
|
|
134
|
+
*
|
|
135
|
+
* ```ts
|
|
136
|
+
* createExpressServer({ config: "./langgraph.json", logger: createConsoleLogger() });
|
|
137
|
+
* ```
|
|
83
138
|
*/
|
|
84
|
-
declare function
|
|
139
|
+
declare function createConsoleLogger(options?: ConsoleLoggerOptions): Logger;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The `run=… thread=… assistant=… node=…` row identifying a failed run. Exported so the framework
|
|
143
|
+
* bridges, which place the stack in their own logger's dedicated slot rather than appending it to
|
|
144
|
+
* the message, still render identity identically — adding a field is then one edit, not three.
|
|
145
|
+
*/
|
|
146
|
+
declare function runFailureIdentity(report: RunFailureReport): string;
|
|
147
|
+
/**
|
|
148
|
+
* Render structured log meta as plain text. Returns `""` when there is nothing to add, so callers can
|
|
149
|
+
* append unconditionally.
|
|
150
|
+
*
|
|
151
|
+
* A `RunFailureReport` renders as its identity row plus the error's stack and `cause` chain — the
|
|
152
|
+
* failure's *whole* story, since this is the one surface guaranteed to receive it (the wire gets only
|
|
153
|
+
* what is safe to hand a caller).
|
|
154
|
+
*/
|
|
155
|
+
declare function formatLogMeta(meta: unknown): string;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* An error's stack (falling back to `name: message`), its `details` when it carries any, and its
|
|
159
|
+
* `cause` chain appended. Depth-capped and cycle-safe; never throws.
|
|
160
|
+
*/
|
|
161
|
+
declare function describeError(thrown: unknown): string;
|
|
85
162
|
|
|
86
163
|
/**
|
|
87
164
|
* The one precedence chain for background-run concurrency: an explicit value (a `worker.maxConcurrency`
|
|
@@ -135,6 +212,13 @@ interface InMemoryRuntimeConfig {
|
|
|
135
212
|
/** Load `langgraph.json`, wiring fresh in-memory drivers and reading its `http.cors` for the adapter. */
|
|
136
213
|
declare function loadInMemoryRuntime(configPath: string, importModule?: ModuleImporter, staticSchemas?: Record<string, GraphSchemas>): Promise<InMemoryRuntimeConfig>;
|
|
137
214
|
interface ReloadableInMemoryRuntime extends InMemoryRuntimeConfig {
|
|
215
|
+
/**
|
|
216
|
+
* The parsed `langgraph.json`, so a caller that needs a block this runtime doesn't act on itself
|
|
217
|
+
* (`telemetry`, say) can read it without a second `loadConfig` — which would re-import every graph.
|
|
218
|
+
*/
|
|
219
|
+
config: LanggraphJson;
|
|
220
|
+
/** Directory holding `langgraph.json`, for resolving paths declared relative to it. */
|
|
221
|
+
configDir: string;
|
|
138
222
|
/**
|
|
139
223
|
* Re-read the config and swap in freshly imported graphs, keeping the same drivers. Because the
|
|
140
224
|
* run engine calls `graphs.load()` per run (it never caches the compiled graph itself), the next
|
|
@@ -153,7 +237,14 @@ interface ReloadableInMemoryRuntime extends InMemoryRuntimeConfig {
|
|
|
153
237
|
* dev` pairs this with vite's watcher (clear vite's cache, then `reloadGraphs()` — no server
|
|
154
238
|
* restart, no lost state) and with on-disk JSON persistence across restarts.
|
|
155
239
|
*/
|
|
156
|
-
declare function loadReloadableInMemoryRuntime(configPath: string, importModule?: ModuleImporter, staticSchemas?: Record<string, GraphSchemas
|
|
240
|
+
declare function loadReloadableInMemoryRuntime(configPath: string, importModule?: ModuleImporter, staticSchemas?: Record<string, GraphSchemas>,
|
|
241
|
+
/**
|
|
242
|
+
* Extra deps to build in, for a caller that acts on a config block this runtime doesn't itself
|
|
243
|
+
* read (`telemetry`). Merged **into** the constructed `deps`, so every consumer sees the same
|
|
244
|
+
* object — patching the returned `deps` afterwards would miss anything that already snapshotted it
|
|
245
|
+
* (`resolveDeps` spreads, it doesn't alias).
|
|
246
|
+
*/
|
|
247
|
+
extraDeps?: Partial<Omit<ProtocolDeps, "graphs">>): Promise<ReloadableInMemoryRuntime>;
|
|
157
248
|
|
|
158
249
|
type AnyCompiledGraph = CompiledGraph<any>;
|
|
159
250
|
/**
|
|
@@ -278,4 +369,4 @@ declare function sendNodeError(error: unknown, res: ServerResponse, logger?: Log
|
|
|
278
369
|
*/
|
|
279
370
|
declare function stripBasePath(pathname: string, basePath: string): string | null;
|
|
280
371
|
|
|
281
|
-
export { type CorsSetting, type DevStateCounts, type DevStateSnapshot, type EmbeddableGraph, type InMemoryRuntimeConfig, type LanggraphCorsConfig, type ReloadableInMemoryRuntime, type ResolvedProtocolRuntime, type ResolvedRuntimeDeps, type SkeinRuntimeCommonOptions, type SkeinRuntimeOptions, allowedOrigin, applyNodeCors, corsFromHttpConfig, corsPreflightHeaders, corsResponseHeaders, createInMemoryDeps, describeSnapshot, embedInMemoryGraphs, graphMapToResolver, joinList, loadInMemoryRuntime, loadReloadableInMemoryRuntime, loadSnapshotIntoStore, normalizeEmbeddableGraphs, readLanggraphDevState, resolveProtocolRuntime, resolveRunConcurrency, resolveRuntimeDeps, resolveShutdownGraceMs, sendNodeError, sendNodePreflight, sendNodeResponse, stripBasePath, toCorsOptions };
|
|
372
|
+
export { type ConsoleLogLevel, type ConsoleLoggerOptions, type CorsSetting, type DevStateCounts, type DevStateSnapshot, type EmbeddableGraph, type InMemoryRuntimeConfig, type LanggraphCorsConfig, type ReloadableInMemoryRuntime, type ResolvedProtocolRuntime, type ResolvedRuntimeDeps, type SkeinRuntimeCommonOptions, type SkeinRuntimeOptions, allowedOrigin, applyNodeCors, corsFromHttpConfig, corsPreflightHeaders, corsResponseHeaders, createConsoleLogger, createInMemoryDeps, describeError, describeSnapshot, embedInMemoryGraphs, formatLogMeta, graphMapToResolver, joinList, loadInMemoryRuntime, loadReloadableInMemoryRuntime, loadSnapshotIntoStore, normalizeEmbeddableGraphs, readLanggraphDevState, resolveProtocolRuntime, resolveRunConcurrency, resolveRuntimeDeps, resolveShutdownGraceMs, runFailureIdentity, sendNodeError, sendNodePreflight, sendNodeResponse, stripBasePath, toCorsOptions };
|
package/dist/index.js
CHANGED
|
@@ -153,7 +153,7 @@ async function loadInMemoryRuntime(configPath, importModule, staticSchemas) {
|
|
|
153
153
|
cors: corsFromHttpConfig(config.http)
|
|
154
154
|
};
|
|
155
155
|
}
|
|
156
|
-
async function loadReloadableInMemoryRuntime(configPath, importModule, staticSchemas) {
|
|
156
|
+
async function loadReloadableInMemoryRuntime(configPath, importModule, staticSchemas, extraDeps) {
|
|
157
157
|
const first = await loadConfig({ configPath, importModule, staticSchemas });
|
|
158
158
|
let current = first.graphs;
|
|
159
159
|
const graphs = {
|
|
@@ -169,11 +169,14 @@ async function loadReloadableInMemoryRuntime(configPath, importModule, staticSch
|
|
|
169
169
|
queue: new MemoryRunQueue2(),
|
|
170
170
|
bus: new MemoryRunEventBus2(),
|
|
171
171
|
checkpointer,
|
|
172
|
-
auth: await loadAuthEngine(first.config.auth, { configDir: first.configDir, importModule })
|
|
172
|
+
auth: await loadAuthEngine(first.config.auth, { configDir: first.configDir, importModule }),
|
|
173
|
+
...extraDeps
|
|
173
174
|
};
|
|
174
175
|
return {
|
|
175
176
|
deps,
|
|
176
177
|
cors: corsFromHttpConfig(first.config.http),
|
|
178
|
+
config: first.config,
|
|
179
|
+
configDir: first.configDir,
|
|
177
180
|
reloadGraphs: async () => {
|
|
178
181
|
current = (await loadConfig({ configPath, importModule, staticSchemas })).graphs;
|
|
179
182
|
},
|
|
@@ -239,13 +242,19 @@ function resolveShutdownGraceMs(explicit, env = process.env) {
|
|
|
239
242
|
}
|
|
240
243
|
|
|
241
244
|
// src/resolve-runtime.ts
|
|
242
|
-
|
|
243
|
-
if (
|
|
244
|
-
|
|
245
|
-
return
|
|
246
|
-
}
|
|
247
|
-
async function
|
|
248
|
-
const { deps, cors:
|
|
245
|
+
function resolveLogger(option, injected, frameworkLogger) {
|
|
246
|
+
if (injected) return injected;
|
|
247
|
+
if (option === false) return void 0;
|
|
248
|
+
return option ?? frameworkLogger;
|
|
249
|
+
}
|
|
250
|
+
async function resolveRuntimeDeps(options, frameworkLogger) {
|
|
251
|
+
const loaded = options.deps ? { deps: options.deps, cors: void 0 } : await loadInMemoryRuntime(options.config, options.importModule);
|
|
252
|
+
const logger = resolveLogger(options.logger, loaded.deps.logger, frameworkLogger);
|
|
253
|
+
if (logger && !loaded.deps.logger) loaded.deps.logger = logger;
|
|
254
|
+
return { deps: loaded.deps, cors: loaded.cors, logger };
|
|
255
|
+
}
|
|
256
|
+
async function resolveProtocolRuntime(options, frameworkLogger) {
|
|
257
|
+
const { deps, cors: corsFromConfig, logger } = await resolveRuntimeDeps(options, frameworkLogger);
|
|
249
258
|
const runtime = createProtocolRuntime(deps, {
|
|
250
259
|
worker: {
|
|
251
260
|
...options.worker,
|
|
@@ -258,13 +267,126 @@ async function resolveProtocolRuntime(options) {
|
|
|
258
267
|
await Promise.all(
|
|
259
268
|
deps.graphs.ids.map(
|
|
260
269
|
(graphId) => deps.graphs.load(graphId).catch((error) => {
|
|
261
|
-
|
|
270
|
+
logger?.warn(`Failed to warm graph "${graphId}".`, error);
|
|
262
271
|
})
|
|
263
272
|
)
|
|
264
273
|
);
|
|
265
274
|
}
|
|
266
275
|
runtime.worker.start();
|
|
267
|
-
return { runtime, cors: corsFromConfig };
|
|
276
|
+
return { runtime, cors: corsFromConfig, logger };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/log-meta.ts
|
|
280
|
+
import { isRunFailureReport } from "@skein-js/agent-protocol";
|
|
281
|
+
|
|
282
|
+
// src/describe-error.ts
|
|
283
|
+
var MAX_CAUSE_DEPTH = 5;
|
|
284
|
+
function readProperty(source, key) {
|
|
285
|
+
try {
|
|
286
|
+
return source[key];
|
|
287
|
+
} catch {
|
|
288
|
+
return void 0;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function safeStringify(value) {
|
|
292
|
+
try {
|
|
293
|
+
return JSON.stringify(value);
|
|
294
|
+
} catch {
|
|
295
|
+
return void 0;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function describe(thrown, depth, seen) {
|
|
299
|
+
if (!(thrown instanceof Error)) {
|
|
300
|
+
return typeof thrown === "object" && thrown !== null ? safeStringify(thrown) ?? String(thrown) : String(thrown);
|
|
301
|
+
}
|
|
302
|
+
const stack = readProperty(thrown, "stack");
|
|
303
|
+
let described = typeof stack === "string" ? stack : `${thrown.name}: ${thrown.message}`;
|
|
304
|
+
const details = readProperty(thrown, "details");
|
|
305
|
+
if (details !== void 0) {
|
|
306
|
+
const rendered = safeStringify(details);
|
|
307
|
+
if (rendered !== void 0) described += `
|
|
308
|
+
details: ${rendered}`;
|
|
309
|
+
}
|
|
310
|
+
if (depth >= MAX_CAUSE_DEPTH || seen.has(thrown)) return described;
|
|
311
|
+
seen.add(thrown);
|
|
312
|
+
const cause = readProperty(thrown, "cause");
|
|
313
|
+
if (cause === void 0) return described;
|
|
314
|
+
return `${described}
|
|
315
|
+
caused by: ${describe(cause, depth + 1, seen)}`;
|
|
316
|
+
}
|
|
317
|
+
function describeError(thrown) {
|
|
318
|
+
return describe(thrown, 0, /* @__PURE__ */ new WeakSet());
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// src/log-meta.ts
|
|
322
|
+
function runFailureIdentity(report) {
|
|
323
|
+
return [
|
|
324
|
+
`run=${report.runId}`,
|
|
325
|
+
`thread=${report.threadId}`,
|
|
326
|
+
`assistant=${report.assistantId}`,
|
|
327
|
+
// Omitted entirely when LangGraph named no node — no `unknown` placeholder, no guess.
|
|
328
|
+
...report.failingNodes.length > 0 ? [`node=${report.failingNodes.join(",")}`] : []
|
|
329
|
+
].join(" ");
|
|
330
|
+
}
|
|
331
|
+
function safeString(value) {
|
|
332
|
+
try {
|
|
333
|
+
return String(value);
|
|
334
|
+
} catch {
|
|
335
|
+
return Object.prototype.toString.call(value);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function safeStringify2(value) {
|
|
339
|
+
try {
|
|
340
|
+
return JSON.stringify(value) ?? safeString(value);
|
|
341
|
+
} catch {
|
|
342
|
+
return safeString(value);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
function renderRecord(meta) {
|
|
346
|
+
let entries;
|
|
347
|
+
try {
|
|
348
|
+
entries = Object.entries(meta);
|
|
349
|
+
} catch {
|
|
350
|
+
return safeString(meta);
|
|
351
|
+
}
|
|
352
|
+
return entries.map(([key, value]) => {
|
|
353
|
+
const rendered = typeof value === "object" && value !== null ? safeStringify2(value) : safeString(value);
|
|
354
|
+
return `${key}=${rendered}`;
|
|
355
|
+
}).join(" ");
|
|
356
|
+
}
|
|
357
|
+
function formatLogMeta(meta) {
|
|
358
|
+
if (meta === void 0 || meta === null) return "";
|
|
359
|
+
if (isRunFailureReport(meta)) return `${runFailureIdentity(meta)}
|
|
360
|
+
${describeError(meta.error)}`;
|
|
361
|
+
if (meta instanceof Error) return describeError(meta);
|
|
362
|
+
if (typeof meta === "object") return renderRecord(meta);
|
|
363
|
+
return safeString(meta);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// src/console-logger.ts
|
|
367
|
+
var LEVELS = ["debug", "info", "warn", "error"];
|
|
368
|
+
function createConsoleLogger(options = {}) {
|
|
369
|
+
const prefix = options.prefix ?? "skein";
|
|
370
|
+
const configured = LEVELS.indexOf(options.level ?? "info");
|
|
371
|
+
const threshold = configured === -1 ? LEVELS.indexOf("info") : configured;
|
|
372
|
+
function emit(level, write) {
|
|
373
|
+
const rank = LEVELS.indexOf(level);
|
|
374
|
+
if (rank < threshold) return () => {
|
|
375
|
+
};
|
|
376
|
+
return (message, meta) => {
|
|
377
|
+
const rendered = formatLogMeta(meta);
|
|
378
|
+
write(`${prefix} ${level}: ${message}${rendered ? `
|
|
379
|
+
${rendered}` : ""}`);
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
return {
|
|
383
|
+
// Bound to `console` rather than passed by reference so a host that swaps `console.log` later
|
|
384
|
+
// (test harnesses do) is still honored at call time.
|
|
385
|
+
debug: emit("debug", (line) => console.debug(line)),
|
|
386
|
+
info: emit("info", (line) => console.log(line)),
|
|
387
|
+
warn: emit("warn", (line) => console.warn(line)),
|
|
388
|
+
error: emit("error", (line) => console.error(line))
|
|
389
|
+
};
|
|
268
390
|
}
|
|
269
391
|
|
|
270
392
|
// src/index.ts
|
|
@@ -717,9 +839,12 @@ export {
|
|
|
717
839
|
corsFromHttpConfig,
|
|
718
840
|
corsPreflightHeaders,
|
|
719
841
|
corsResponseHeaders,
|
|
842
|
+
createConsoleLogger,
|
|
720
843
|
createInMemoryDeps,
|
|
844
|
+
describeError,
|
|
721
845
|
describeSnapshot,
|
|
722
846
|
embedInMemoryGraphs,
|
|
847
|
+
formatLogMeta,
|
|
723
848
|
graphMapToResolver,
|
|
724
849
|
joinList,
|
|
725
850
|
loadInMemoryRuntime,
|
|
@@ -731,6 +856,7 @@ export {
|
|
|
731
856
|
resolveRunConcurrency,
|
|
732
857
|
resolveRuntimeDeps,
|
|
733
858
|
resolveShutdownGraceMs,
|
|
859
|
+
runFailureIdentity,
|
|
734
860
|
sendNodeError,
|
|
735
861
|
sendNodePreflight,
|
|
736
862
|
sendNodeResponse,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skein-js/server-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.2",
|
|
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>",
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"cors": "^2.8.5",
|
|
45
45
|
"superjson": "^2.2.6",
|
|
46
46
|
"zod": "^3.25.76",
|
|
47
|
-
"@skein-js/agent-protocol": "0.
|
|
48
|
-
"@skein-js/
|
|
49
|
-
"@skein-js/
|
|
50
|
-
"@skein-js/core": "0.
|
|
47
|
+
"@skein-js/agent-protocol": "0.11.2",
|
|
48
|
+
"@skein-js/storage-memory": "0.11.2",
|
|
49
|
+
"@skein-js/config": "0.11.2",
|
|
50
|
+
"@skein-js/core": "0.11.2"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"@langchain/langgraph": "^1.4.0"
|