@skein-js/agent-protocol 0.7.0 → 0.9.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/dist/index.d.ts +79 -12
- package/dist/index.js +315 -81
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GraphSchema, SkeinStore, RunQueue, RunEventBus, AuthEngine, AuthUser, Metadata, Thread, ThreadSearchQuery, ThreadState, Assistant, AssistantSearchQuery, AssistantCreate, AssistantUpdate, AssistantVersionsQuery, AssistantVersion, AssistantGraph, Config, StreamMode, MultitaskStrategy, RunFrame, DefaultValues, Run, RunStatus, StorePutOptions, Item, StoreSearchQuery, SearchItem, StoreRepo } from '@skein-js/core';
|
|
1
|
+
import { GraphSchema, SkeinStore, RunQueue, RunEventBus, AuthEngine, AuthUser, Metadata, Thread, ThreadSearchQuery, ThreadState, Checkpoint, Assistant, AssistantSearchQuery, AssistantCreate, AssistantUpdate, AssistantVersionsQuery, AssistantVersion, AssistantGraph, Config, StreamMode, MultitaskStrategy, RunFrame, DefaultValues, Run, RunStatus, StorePutOptions, Item, StoreSearchQuery, SearchItem, StoreRepo } from '@skein-js/core';
|
|
2
2
|
import { CompiledGraph, BaseCheckpointSaver, BaseStore, Item as Item$1, Operation, OperationResults } from '@langchain/langgraph';
|
|
3
3
|
|
|
4
4
|
/** A factory export: called (optionally with per-run config) to produce a compiled graph. */
|
|
@@ -184,6 +184,17 @@ interface PatchThreadInput {
|
|
|
184
184
|
interface HistoryOptions {
|
|
185
185
|
limit?: number;
|
|
186
186
|
}
|
|
187
|
+
/** Body of `POST /threads/{id}/state` — a time-travel update that forks a new checkpoint. */
|
|
188
|
+
interface UpdateStateInput {
|
|
189
|
+
/** New state to write. `null`/`undefined` re-points `next` without changing values. */
|
|
190
|
+
values?: unknown;
|
|
191
|
+
/** Attribute the update as though this node produced `values` (sets up which node runs next). */
|
|
192
|
+
as_node?: string;
|
|
193
|
+
/** The checkpoint to fork from; omitted updates the thread tip. */
|
|
194
|
+
checkpoint_id?: string;
|
|
195
|
+
/** Full checkpoint pointer to fork from (alternative to `checkpoint_id`). */
|
|
196
|
+
checkpoint?: Record<string, unknown>;
|
|
197
|
+
}
|
|
187
198
|
interface ThreadService {
|
|
188
199
|
create(input?: CreateThreadInput): Promise<Thread>;
|
|
189
200
|
get(threadId: string): Promise<Thread>;
|
|
@@ -197,6 +208,15 @@ interface ThreadService {
|
|
|
197
208
|
history(threadId: string, options?: HistoryOptions): Promise<ThreadState[]>;
|
|
198
209
|
/** The thread's current state snapshot — `GET /threads/{id}/state`, what `useStream` hydrates from. */
|
|
199
210
|
getState(threadId: string): Promise<ThreadState>;
|
|
211
|
+
/** State at a specific checkpoint (time travel) — `GET /threads/{id}/state/{checkpoint_id}`. */
|
|
212
|
+
getStateAt(threadId: string, checkpointId: string): Promise<ThreadState>;
|
|
213
|
+
/**
|
|
214
|
+
* Update (fork) thread state at a checkpoint — `POST /threads/{id}/state`. Writes a new checkpoint
|
|
215
|
+
* via `graph.updateState`, mirrors it onto the thread row, and returns the new checkpoint pointer.
|
|
216
|
+
*/
|
|
217
|
+
updateState(threadId: string, input: UpdateStateInput): Promise<{
|
|
218
|
+
checkpoint: Checkpoint;
|
|
219
|
+
}>;
|
|
200
220
|
}
|
|
201
221
|
|
|
202
222
|
/** `POST /assistants` — create input plus LangGraph's `if_exists` conflict policy. */
|
|
@@ -266,6 +286,8 @@ interface CreateRunInput {
|
|
|
266
286
|
interrupt_after?: string[] | "*";
|
|
267
287
|
/** Absolute `http(s)` URL POSTed with the settled run once it reaches a terminal status. */
|
|
268
288
|
webhook?: string;
|
|
289
|
+
/** Time travel: fork this run from a prior checkpoint instead of the thread tip (server-validated). */
|
|
290
|
+
checkpoint_id?: string;
|
|
269
291
|
}
|
|
270
292
|
/** A started streaming run: its id, plus the live frame iterable to serialize as SSE. */
|
|
271
293
|
interface StartedStream {
|
|
@@ -352,6 +374,12 @@ interface ProtocolRequest {
|
|
|
352
374
|
query: Record<string, string | string[] | undefined>;
|
|
353
375
|
body: unknown;
|
|
354
376
|
headers: Record<string, string | undefined>;
|
|
377
|
+
/**
|
|
378
|
+
* Aborts when the client goes away, so a handler can stop work the caller will never read.
|
|
379
|
+
* Optional: an adapter that can't observe disconnects simply omits it. Currently honored by the
|
|
380
|
+
* single-graph invoke surface; protocol runs carry their own cancellation through the run row.
|
|
381
|
+
*/
|
|
382
|
+
signal?: AbortSignal;
|
|
355
383
|
}
|
|
356
384
|
/** A normalized response an adapter serializes back onto its framework response. */
|
|
357
385
|
type ProtocolResponse = {
|
|
@@ -387,6 +415,8 @@ interface ProtocolHandlers {
|
|
|
387
415
|
deleteThread: ProtocolHandler;
|
|
388
416
|
getThreadHistory: ProtocolHandler;
|
|
389
417
|
getThreadState: ProtocolHandler;
|
|
418
|
+
getThreadStateAtCheckpoint: ProtocolHandler;
|
|
419
|
+
updateThreadState: ProtocolHandler;
|
|
390
420
|
createWaitRun: ProtocolHandler;
|
|
391
421
|
createStreamRun: ProtocolHandler;
|
|
392
422
|
createBackgroundRun: ProtocolHandler;
|
|
@@ -442,11 +472,16 @@ interface ProtocolRuntime {
|
|
|
442
472
|
declare function createProtocolRuntime(deps: ProtocolDeps, options?: ProtocolRuntimeOptions): ProtocolRuntime;
|
|
443
473
|
|
|
444
474
|
type HttpMethod = "get" | "post" | "put" | "patch" | "delete";
|
|
445
|
-
|
|
475
|
+
/**
|
|
476
|
+
* One route. `HandlerName` defaults to a member of the protocol handler table; a surface mounted
|
|
477
|
+
* outside that table (the single-graph invoke endpoint) parameterizes it with its own handler names,
|
|
478
|
+
* so `handler` never has to lie about being a `keyof ProtocolHandlers` an adapter could look up.
|
|
479
|
+
*/
|
|
480
|
+
interface RouteBinding<HandlerName = keyof ProtocolHandlers> {
|
|
446
481
|
method: HttpMethod;
|
|
447
482
|
/** Path with `:param` placeholders, e.g. `/threads/:thread_id/runs/stream`. */
|
|
448
483
|
path: string;
|
|
449
|
-
handler:
|
|
484
|
+
handler: HandlerName;
|
|
450
485
|
/**
|
|
451
486
|
* Fold the path `thread_id` into the request body before dispatch. The SDK addresses a
|
|
452
487
|
* thread-scoped run by its path (`POST /threads/{id}/runs/stream`) while carrying only
|
|
@@ -469,18 +504,50 @@ declare function copyThreadIdIntoBody(request: ProtocolRequest): ProtocolRequest
|
|
|
469
504
|
*/
|
|
470
505
|
declare const foldThreadId: typeof copyThreadIdIntoBody;
|
|
471
506
|
/** A resolved route: the matched binding plus the path params extracted from the URL. */
|
|
472
|
-
interface RouteMatch {
|
|
473
|
-
binding: RouteBinding
|
|
507
|
+
interface RouteMatch<HandlerName = keyof ProtocolHandlers> {
|
|
508
|
+
binding: RouteBinding<HandlerName>;
|
|
474
509
|
params: Record<string, string>;
|
|
475
510
|
}
|
|
511
|
+
/** Matches a `method` + `pathname` against a fixed route table. Built by {@link createRouteMatcher}. */
|
|
512
|
+
type RouteMatcher<HandlerName = keyof ProtocolHandlers> = (method: string, pathname: string) => RouteMatch<HandlerName> | undefined;
|
|
513
|
+
/**
|
|
514
|
+
* Build a matcher over any route table — the protocol's own, or the simplified invoke surface's.
|
|
515
|
+
* Each `:param` path is compiled to a named-group regex once, anchored (`^…$`) so a literal segment
|
|
516
|
+
* can't be matched as a param value. The returned matcher iterates in table order, which is
|
|
517
|
+
* most-specific-first, so a literal segment wins over a `:param`.
|
|
518
|
+
*/
|
|
519
|
+
declare function createRouteMatcher<HandlerName>(bindings: readonly RouteBinding<HandlerName>[]): RouteMatcher<HandlerName>;
|
|
520
|
+
/**
|
|
521
|
+
* Match a `method` + `pathname` (no query string) against the Agent Protocol route table. This is
|
|
522
|
+
* what adapters that dispatch from a catch-all route (NestJS middleware, Next.js route handlers) use
|
|
523
|
+
* in place of a framework router; Express/Fastify bind `skeinRoutes` to their native router instead.
|
|
524
|
+
*/
|
|
525
|
+
declare const matchSkeinRoute: RouteMatcher;
|
|
526
|
+
|
|
527
|
+
/** The default path prefix the invoke endpoint mounts under. */
|
|
528
|
+
declare const DEFAULT_INVOKE_PREFIX = "/invoke";
|
|
529
|
+
/** Options for {@link createGraphInvokeHandler}. */
|
|
530
|
+
interface GraphInvokeOptions {
|
|
531
|
+
/**
|
|
532
|
+
* Stream modes used when the caller opts into SSE, overridable per request via `?stream_mode=`.
|
|
533
|
+
* Defaults to `"values"` — each frame is the full state after a step, ending at the same value the
|
|
534
|
+
* JSON response would have returned.
|
|
535
|
+
*/
|
|
536
|
+
streamMode?: StreamMode | StreamMode[];
|
|
537
|
+
}
|
|
538
|
+
/** The single handler name this surface binds — deliberately not a `keyof ProtocolHandlers`. */
|
|
539
|
+
type GraphInvokeHandlerName = "invokeGraph";
|
|
540
|
+
/**
|
|
541
|
+
* The route table for the invoke surface — one POST, shaped like {@link skeinRoutes} so catch-all
|
|
542
|
+
* adapters (NestJS, Next.js) can match it the same way and native routers can bind it directly.
|
|
543
|
+
* Parameterized with its own handler name, so nothing can mistake it for a protocol-table lookup key.
|
|
544
|
+
*/
|
|
545
|
+
declare function graphInvokeRoutes(prefix?: string): RouteBinding<GraphInvokeHandlerName>[];
|
|
476
546
|
/**
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
* most-specific-first, so a literal segment wins over a `:param`. This is what adapters that dispatch
|
|
480
|
-
* from a catch-all route (NestJS middleware, Next.js route handlers) use in place of a framework
|
|
481
|
-
* router; Express/Fastify bind `skeinRoutes` to their native router instead.
|
|
547
|
+
* Build the handler for `POST <prefix>/:graph_id`. Returns a {@link ProtocolHandler}, so every
|
|
548
|
+
* adapter serializes it through the same JSON/SSE path the protocol routes already use.
|
|
482
549
|
*/
|
|
483
|
-
declare function
|
|
550
|
+
declare function createGraphInvokeHandler(deps: ProtocolDeps, options?: GraphInvokeOptions): ProtocolHandler;
|
|
484
551
|
|
|
485
552
|
type LangGraphSearchItem = Item$1 & {
|
|
486
553
|
score?: number;
|
|
@@ -535,4 +602,4 @@ declare function toSseEvents(frames: AsyncIterable<RunFrame>, finalStatus: () =>
|
|
|
535
602
|
*/
|
|
536
603
|
declare function parseAfterSeq(lastEventId: string | undefined): number;
|
|
537
604
|
|
|
538
|
-
export { type AssistantService, type Clock, type CommandInput, type CompiledGraphFactory, type CreateAssistantInput, type CreateRunInput, type CreateThreadInput, type DeleteAssistantOptions, type DrawGraphOptions, type GraphResolver, type GraphSchemas, type HistoryOptions, type HttpMethod, type Logger, type PatchThreadInput, type ProtocolContext, type ProtocolDeps, type ProtocolHandler, type ProtocolHandlers, type ProtocolRequest, type ProtocolResponse, type ProtocolRuntime, type ProtocolRuntimeOptions, type ProtocolService, type ResolvedGraph, type RouteBinding, type RouteMatch, type RunService, type RunWorker, type RunWorkerOptions, SSE_HEADERS, SkeinBaseStore, type StartedStream, type StoreService, type SubgraphsOptions, type ThreadService, type ThreadStreamInput, type ThreadStreamService, buildProtocolService, copyThreadIdIntoBody, createContext, createProtocolHandlers, createProtocolRuntime, createProtocolService, createProtocolServiceFromContext, createRunWorker, encodeFrame, encodeTerminal, foldThreadId, matchSkeinRoute, parseAfterSeq, skeinRoutes, toSseEvents };
|
|
605
|
+
export { type AssistantService, type Clock, type CommandInput, type CompiledGraphFactory, type CreateAssistantInput, type CreateRunInput, type CreateThreadInput, DEFAULT_INVOKE_PREFIX, type DeleteAssistantOptions, type DrawGraphOptions, type GraphInvokeHandlerName, type GraphInvokeOptions, type GraphResolver, type GraphSchemas, type HistoryOptions, type HttpMethod, type Logger, type PatchThreadInput, type ProtocolContext, type ProtocolDeps, type ProtocolHandler, type ProtocolHandlers, type ProtocolRequest, type ProtocolResponse, type ProtocolRuntime, type ProtocolRuntimeOptions, type ProtocolService, type ResolvedGraph, type RouteBinding, type RouteMatch, type RouteMatcher, type RunService, type RunWorker, type RunWorkerOptions, SSE_HEADERS, SkeinBaseStore, type StartedStream, type StoreService, type SubgraphsOptions, type ThreadService, type ThreadStreamInput, type ThreadStreamService, buildProtocolService, copyThreadIdIntoBody, createContext, createGraphInvokeHandler, createProtocolHandlers, createProtocolRuntime, createProtocolService, createProtocolServiceFromContext, createRouteMatcher, createRunWorker, encodeFrame, encodeTerminal, foldThreadId, graphInvokeRoutes, matchSkeinRoute, parseAfterSeq, skeinRoutes, toSseEvents };
|
package/dist/index.js
CHANGED
|
@@ -64,6 +64,11 @@ var streamModeSchema = z.union([z.string(), z.array(z.string())]);
|
|
|
64
64
|
var configSchema = z.record(z.unknown());
|
|
65
65
|
var multitaskStrategySchema = z.enum(["reject", "interrupt", "rollback", "enqueue"]);
|
|
66
66
|
var interruptWhenSchema = z.union([z.array(z.string()), z.literal("*")]);
|
|
67
|
+
var checkpointSchema = z.object({
|
|
68
|
+
checkpoint_id: z.string().optional(),
|
|
69
|
+
checkpoint_ns: z.string().nullish(),
|
|
70
|
+
checkpoint_map: z.record(z.unknown()).nullish()
|
|
71
|
+
});
|
|
67
72
|
var runCreateSchema = z.object({
|
|
68
73
|
assistant_id: z.string().min(1),
|
|
69
74
|
thread_id: z.string().min(1).optional(),
|
|
@@ -77,7 +82,21 @@ var runCreateSchema = z.object({
|
|
|
77
82
|
interrupt_before: interruptWhenSchema.optional(),
|
|
78
83
|
interrupt_after: interruptWhenSchema.optional(),
|
|
79
84
|
/** Run-completion webhook: an absolute `http(s)` URL POSTed the settled run when it finishes. */
|
|
80
|
-
webhook: z.string().url().optional()
|
|
85
|
+
webhook: z.string().url().optional(),
|
|
86
|
+
/** Time travel: fork this run from a prior checkpoint instead of the thread tip. */
|
|
87
|
+
checkpoint_id: z.string().optional(),
|
|
88
|
+
/** Time travel: full checkpoint pointer to fork from (its `checkpoint_id` is what matters). */
|
|
89
|
+
checkpoint: checkpointSchema.optional()
|
|
90
|
+
}).passthrough();
|
|
91
|
+
var threadStateUpdateSchema = z.object({
|
|
92
|
+
/** New state to write. `null` re-points `next` without changing values; an array is a bulk write. */
|
|
93
|
+
values: z.union([z.record(z.unknown()), z.array(z.record(z.unknown()))]).nullish(),
|
|
94
|
+
/** Attribute the update as though this node produced `values` (sets up which node runs next). */
|
|
95
|
+
as_node: z.string().optional(),
|
|
96
|
+
/** The checkpoint to fork from; omitted updates the thread tip. */
|
|
97
|
+
checkpoint_id: z.string().optional(),
|
|
98
|
+
/** Full checkpoint pointer to fork from (alternative to `checkpoint_id`). */
|
|
99
|
+
checkpoint: checkpointSchema.nullish()
|
|
81
100
|
}).passthrough();
|
|
82
101
|
var threadStreamSchema = z.object({
|
|
83
102
|
assistant_id: z.string().min(1),
|
|
@@ -321,6 +340,23 @@ function createProtocolHandlers(service) {
|
|
|
321
340
|
return json(await service.threads.history(requireParam(req.params, "thread_id"), options));
|
|
322
341
|
},
|
|
323
342
|
getThreadState: async (req) => json(await service.threads.getState(requireParam(req.params, "thread_id"))),
|
|
343
|
+
getThreadStateAtCheckpoint: async (req) => json(
|
|
344
|
+
await service.threads.getStateAt(
|
|
345
|
+
requireParam(req.params, "thread_id"),
|
|
346
|
+
requireParam(req.params, "checkpoint_id")
|
|
347
|
+
)
|
|
348
|
+
),
|
|
349
|
+
updateThreadState: async (req) => {
|
|
350
|
+
const body = parse(threadStateUpdateSchema, req.body ?? {});
|
|
351
|
+
return json(
|
|
352
|
+
await service.threads.updateState(requireParam(req.params, "thread_id"), {
|
|
353
|
+
values: body.values,
|
|
354
|
+
as_node: body.as_node,
|
|
355
|
+
checkpoint_id: body.checkpoint_id,
|
|
356
|
+
checkpoint: body.checkpoint ?? void 0
|
|
357
|
+
})
|
|
358
|
+
);
|
|
359
|
+
},
|
|
324
360
|
// --- runs ---------------------------------------------------------------------------------
|
|
325
361
|
createWaitRun: async (req) => json(await service.runs.createWait(parse(runCreateSchema, req.body))),
|
|
326
362
|
createStreamRun: async (req) => {
|
|
@@ -722,50 +758,6 @@ import {
|
|
|
722
758
|
SkeinHttpError as SkeinHttpError4
|
|
723
759
|
} from "@skein-js/core";
|
|
724
760
|
|
|
725
|
-
// src/normalize-error.ts
|
|
726
|
-
import { isSkeinHttpError as isSkeinHttpError2, SkeinHttpError as SkeinHttpError3 } from "@skein-js/core";
|
|
727
|
-
function serializeError(error) {
|
|
728
|
-
if (error instanceof Error) {
|
|
729
|
-
return { name: error.name, message: error.message };
|
|
730
|
-
}
|
|
731
|
-
return { name: "Error", message: String(error) };
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
// src/sse/run-frame-stream.ts
|
|
735
|
-
var STREAM_MODES = [
|
|
736
|
-
"values",
|
|
737
|
-
"updates",
|
|
738
|
-
"messages",
|
|
739
|
-
"messages-tuple",
|
|
740
|
-
"custom",
|
|
741
|
-
"events",
|
|
742
|
-
"debug"
|
|
743
|
-
];
|
|
744
|
-
function isStreamMode(value) {
|
|
745
|
-
return typeof value === "string" && STREAM_MODES.includes(value);
|
|
746
|
-
}
|
|
747
|
-
function chunkToFrameBody(chunk) {
|
|
748
|
-
if (Array.isArray(chunk) && chunk.length === 2 && isStreamMode(chunk[0])) {
|
|
749
|
-
return { event: chunk[0], data: chunk[1] };
|
|
750
|
-
}
|
|
751
|
-
return { event: "updates", data: chunk };
|
|
752
|
-
}
|
|
753
|
-
function toRunFrame(seq, body) {
|
|
754
|
-
return { seq, event: body.event, data: body.data };
|
|
755
|
-
}
|
|
756
|
-
function streamEventToFrameBody(event, runId, graphModes) {
|
|
757
|
-
if (event.tags?.includes("langsmith:hidden")) return null;
|
|
758
|
-
if (event.event === "on_chain_stream" && event.run_id === runId) {
|
|
759
|
-
const chunk = event.data?.chunk;
|
|
760
|
-
if (Array.isArray(chunk) && chunk.length === 2 && isStreamMode(chunk[0])) {
|
|
761
|
-
const mode = chunk[0];
|
|
762
|
-
return graphModes.includes(mode) ? { event: mode, data: chunk[1] } : null;
|
|
763
|
-
}
|
|
764
|
-
return null;
|
|
765
|
-
}
|
|
766
|
-
return { event: "events", data: event };
|
|
767
|
-
}
|
|
768
|
-
|
|
769
761
|
// src/store/skein-base-store.ts
|
|
770
762
|
import {
|
|
771
763
|
BaseStore
|
|
@@ -842,6 +834,60 @@ var SkeinBaseStore = class extends BaseStore {
|
|
|
842
834
|
}
|
|
843
835
|
};
|
|
844
836
|
|
|
837
|
+
// src/graphs/resolve-compiled-graph.ts
|
|
838
|
+
async function resolveCompiledGraph(graphs, graphId, attachments) {
|
|
839
|
+
const resolved = await graphs.load(graphId);
|
|
840
|
+
const shared = typeof resolved === "function" ? await resolved({ configurable: attachments.configurable }) : resolved;
|
|
841
|
+
const graph = Object.create(shared);
|
|
842
|
+
graph.checkpointer = attachments.checkpointer;
|
|
843
|
+
graph.store = new SkeinBaseStore(attachments.store);
|
|
844
|
+
return graph;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// src/normalize-error.ts
|
|
848
|
+
import { isSkeinHttpError as isSkeinHttpError2, SkeinHttpError as SkeinHttpError3 } from "@skein-js/core";
|
|
849
|
+
function serializeError(error) {
|
|
850
|
+
if (error instanceof Error) {
|
|
851
|
+
return { name: error.name, message: error.message };
|
|
852
|
+
}
|
|
853
|
+
return { name: "Error", message: String(error) };
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// src/sse/run-frame-stream.ts
|
|
857
|
+
var STREAM_MODES = [
|
|
858
|
+
"values",
|
|
859
|
+
"updates",
|
|
860
|
+
"messages",
|
|
861
|
+
"messages-tuple",
|
|
862
|
+
"custom",
|
|
863
|
+
"events",
|
|
864
|
+
"debug"
|
|
865
|
+
];
|
|
866
|
+
function isStreamMode(value) {
|
|
867
|
+
return typeof value === "string" && STREAM_MODES.includes(value);
|
|
868
|
+
}
|
|
869
|
+
function chunkToFrameBody(chunk) {
|
|
870
|
+
if (Array.isArray(chunk) && chunk.length === 2 && isStreamMode(chunk[0])) {
|
|
871
|
+
return { event: chunk[0], data: chunk[1] };
|
|
872
|
+
}
|
|
873
|
+
return { event: "updates", data: chunk };
|
|
874
|
+
}
|
|
875
|
+
function toRunFrame(seq, body) {
|
|
876
|
+
return { seq, event: body.event, data: body.data };
|
|
877
|
+
}
|
|
878
|
+
function streamEventToFrameBody(event, runId, graphModes) {
|
|
879
|
+
if (event.tags?.includes("langsmith:hidden")) return null;
|
|
880
|
+
if (event.event === "on_chain_stream" && event.run_id === runId) {
|
|
881
|
+
const chunk = event.data?.chunk;
|
|
882
|
+
if (Array.isArray(chunk) && chunk.length === 2 && isStreamMode(chunk[0])) {
|
|
883
|
+
const mode = chunk[0];
|
|
884
|
+
return graphModes.includes(mode) ? { event: mode, data: chunk[1] } : null;
|
|
885
|
+
}
|
|
886
|
+
return null;
|
|
887
|
+
}
|
|
888
|
+
return { event: "events", data: event };
|
|
889
|
+
}
|
|
890
|
+
|
|
845
891
|
// src/runs/run-status.ts
|
|
846
892
|
import { isTerminalRunStatus } from "@skein-js/core";
|
|
847
893
|
function threadStatusForRun(status) {
|
|
@@ -990,10 +1036,15 @@ function toFactoryConfigurable(kwargs) {
|
|
|
990
1036
|
}
|
|
991
1037
|
function toGraphCallOptions(kwargs, threadId, signal) {
|
|
992
1038
|
const options = {
|
|
993
|
-
// Drop server-owned keys from the client's configurable, force this thread's id,
|
|
994
|
-
//
|
|
1039
|
+
// Drop server-owned keys from the client's configurable, force this thread's id, add the
|
|
1040
|
+
// server-owned time-travel fork target (if any) *after* sanitizing so the client can never spoof
|
|
1041
|
+
// it, then stamp the authenticated caller so the graph can authorize off `langgraph_auth_user`.
|
|
995
1042
|
configurable: withAuthUser(
|
|
996
|
-
{
|
|
1043
|
+
{
|
|
1044
|
+
...sanitizeConfigurable(kwargs.config?.configurable),
|
|
1045
|
+
thread_id: threadId,
|
|
1046
|
+
...kwargs.checkpoint_id !== void 0 ? { checkpoint_id: kwargs.checkpoint_id } : {}
|
|
1047
|
+
},
|
|
997
1048
|
kwargs.auth_user,
|
|
998
1049
|
kwargs.auth_scopes
|
|
999
1050
|
),
|
|
@@ -1084,16 +1135,11 @@ function abortedStatus(reason) {
|
|
|
1084
1135
|
return "cancelled";
|
|
1085
1136
|
}
|
|
1086
1137
|
async function resolveGraph(deps, graphId, kwargs) {
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
await resolved({ configurable: toFactoryConfigurable(kwargs) })
|
|
1093
|
-
) : resolved;
|
|
1094
|
-
graph.checkpointer = deps.checkpointer;
|
|
1095
|
-
graph.store = new SkeinBaseStore(deps.store.store);
|
|
1096
|
-
return graph;
|
|
1138
|
+
return resolveCompiledGraph(deps.graphs, graphId, {
|
|
1139
|
+
configurable: toFactoryConfigurable(kwargs),
|
|
1140
|
+
checkpointer: deps.checkpointer,
|
|
1141
|
+
store: deps.store.store
|
|
1142
|
+
});
|
|
1097
1143
|
}
|
|
1098
1144
|
async function finalizeRun(deps, runId, status) {
|
|
1099
1145
|
const fresh = await deps.store.runs.get(runId);
|
|
@@ -1334,6 +1380,7 @@ function toKwargs(input, authUser, authScopes) {
|
|
|
1334
1380
|
if (input.interrupt_before !== void 0) kwargs.interrupt_before = input.interrupt_before;
|
|
1335
1381
|
if (input.interrupt_after !== void 0) kwargs.interrupt_after = input.interrupt_after;
|
|
1336
1382
|
if (input.webhook !== void 0) kwargs.webhook = input.webhook;
|
|
1383
|
+
if (input.checkpoint_id !== void 0) kwargs.checkpoint_id = input.checkpoint_id;
|
|
1337
1384
|
if (authUser !== void 0) {
|
|
1338
1385
|
kwargs.auth_user = authUser;
|
|
1339
1386
|
if (authScopes !== void 0) kwargs.auth_scopes = authScopes;
|
|
@@ -1554,13 +1601,13 @@ function createThreadService(ctx) {
|
|
|
1554
1601
|
if (!thread) throw SkeinHttpError7.notFound(`Thread "${threadId}" not found.`);
|
|
1555
1602
|
return thread;
|
|
1556
1603
|
};
|
|
1557
|
-
const
|
|
1604
|
+
const loadThreadGraph = async (threadId) => {
|
|
1558
1605
|
await requireThread(threadId);
|
|
1559
1606
|
const runs = await deps.store.runs.listByThread(threadId);
|
|
1560
1607
|
const latest = [...runs].sort((a, b) => b.created_at.localeCompare(a.created_at))[0];
|
|
1561
|
-
if (!latest) return
|
|
1608
|
+
if (!latest) return void 0;
|
|
1562
1609
|
const assistant = await deps.store.assistants.get(latest.assistant_id);
|
|
1563
|
-
if (!assistant) return
|
|
1610
|
+
if (!assistant) return void 0;
|
|
1564
1611
|
const resolved = await deps.graphs.load(assistant.graph_id);
|
|
1565
1612
|
let graph;
|
|
1566
1613
|
if (typeof resolved === "function") {
|
|
@@ -1570,6 +1617,11 @@ function createThreadService(ctx) {
|
|
|
1570
1617
|
graph = resolved;
|
|
1571
1618
|
}
|
|
1572
1619
|
graph.checkpointer = deps.checkpointer;
|
|
1620
|
+
return graph;
|
|
1621
|
+
};
|
|
1622
|
+
const readHistory = async (threadId, options) => {
|
|
1623
|
+
const graph = await loadThreadGraph(threadId);
|
|
1624
|
+
if (!graph) return [];
|
|
1573
1625
|
const states = [];
|
|
1574
1626
|
const limit = options?.limit;
|
|
1575
1627
|
for await (const snapshot of graph.getStateHistory({
|
|
@@ -1626,6 +1678,45 @@ function createThreadService(ctx) {
|
|
|
1626
1678
|
async getState(threadId) {
|
|
1627
1679
|
const [current] = await readHistory(threadId, { limit: 1 });
|
|
1628
1680
|
return current ?? emptyThreadState(threadId);
|
|
1681
|
+
},
|
|
1682
|
+
async getStateAt(threadId, checkpointId) {
|
|
1683
|
+
const graph = await loadThreadGraph(threadId);
|
|
1684
|
+
if (!graph) return emptyThreadState(threadId);
|
|
1685
|
+
const snapshot = await graph.getState({
|
|
1686
|
+
configurable: { thread_id: threadId, checkpoint_ns: "", checkpoint_id: checkpointId }
|
|
1687
|
+
});
|
|
1688
|
+
return snapshotToThreadState(snapshot);
|
|
1689
|
+
},
|
|
1690
|
+
async updateState(threadId, input) {
|
|
1691
|
+
const graph = await loadThreadGraph(threadId);
|
|
1692
|
+
if (!graph) {
|
|
1693
|
+
throw SkeinHttpError7.unprocessable(`Thread "${threadId}" has no graph to update state on.`);
|
|
1694
|
+
}
|
|
1695
|
+
if (await deps.store.runs.hasActiveRun(threadId)) {
|
|
1696
|
+
throw SkeinHttpError7.conflict(
|
|
1697
|
+
`Thread "${threadId}" is busy; wait for its active run to finish before updating state.`
|
|
1698
|
+
);
|
|
1699
|
+
}
|
|
1700
|
+
const configurable = {
|
|
1701
|
+
checkpoint_ns: "",
|
|
1702
|
+
...input.checkpoint ?? {},
|
|
1703
|
+
...input.checkpoint_id !== void 0 ? { checkpoint_id: input.checkpoint_id } : {},
|
|
1704
|
+
thread_id: threadId
|
|
1705
|
+
};
|
|
1706
|
+
const nextConfig = await graph.updateState({ configurable }, input.values, input.as_node);
|
|
1707
|
+
const snapshot = await graph.getState({ configurable: { thread_id: threadId } });
|
|
1708
|
+
await deps.store.threads.update(
|
|
1709
|
+
threadId,
|
|
1710
|
+
snapshotToThreadUpdate(snapshot, runStatusForSnapshot(snapshot))
|
|
1711
|
+
);
|
|
1712
|
+
const next = nextConfig.configurable ?? {};
|
|
1713
|
+
const checkpoint = {
|
|
1714
|
+
thread_id: threadId,
|
|
1715
|
+
checkpoint_ns: next["checkpoint_ns"] ?? "",
|
|
1716
|
+
checkpoint_id: next["checkpoint_id"],
|
|
1717
|
+
checkpoint_map: next["checkpoint_map"]
|
|
1718
|
+
};
|
|
1719
|
+
return { checkpoint };
|
|
1629
1720
|
}
|
|
1630
1721
|
};
|
|
1631
1722
|
}
|
|
@@ -1828,9 +1919,12 @@ var ROUTE_AUTHZ = {
|
|
|
1828
1919
|
copyThread: { resource: "threads", action: "create" },
|
|
1829
1920
|
getThread: { resource: "threads", action: "read" },
|
|
1830
1921
|
getThreadState: { resource: "threads", action: "read" },
|
|
1922
|
+
getThreadStateAtCheckpoint: { resource: "threads", action: "read" },
|
|
1831
1923
|
getThreadHistory: { resource: "threads", action: "read" },
|
|
1832
1924
|
listThreads: { resource: "threads", action: "search" },
|
|
1833
1925
|
patchThread: { resource: "threads", action: "update" },
|
|
1926
|
+
// Time-travel state update forks a checkpoint — a write, so read-only principals can't fork.
|
|
1927
|
+
updateThreadState: { resource: "threads", action: "update" },
|
|
1834
1928
|
deleteThread: { resource: "threads", action: "delete" },
|
|
1835
1929
|
// runs (authorized through the owning thread)
|
|
1836
1930
|
createWaitRun: { resource: "threads", action: "create_run" },
|
|
@@ -1871,27 +1965,29 @@ function synthesizeRequest(req) {
|
|
|
1871
1965
|
});
|
|
1872
1966
|
}
|
|
1873
1967
|
|
|
1874
|
-
// src/auth/
|
|
1968
|
+
// src/auth/authenticate-request.ts
|
|
1875
1969
|
var STUDIO_USER = {
|
|
1876
1970
|
identity: "langgraph-studio-user",
|
|
1877
1971
|
display_name: "langgraph-studio-user",
|
|
1878
1972
|
is_authenticated: true,
|
|
1879
1973
|
permissions: []
|
|
1880
1974
|
};
|
|
1975
|
+
async function resolveAuthContext(engine, req) {
|
|
1976
|
+
if (!engine.studioAuthDisabled && req.headers["x-auth-scheme"] === "langsmith") {
|
|
1977
|
+
return { user: STUDIO_USER, scopes: [] };
|
|
1978
|
+
}
|
|
1979
|
+
return engine.authenticate(synthesizeRequest(req));
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
// src/auth/authorizing-handlers.ts
|
|
1881
1983
|
function createAuthorizingHandlers(context, engine) {
|
|
1882
1984
|
const baseHandlers = createProtocolHandlers(createProtocolServiceFromContext(context));
|
|
1883
1985
|
const names = Object.keys(ROUTE_AUTHZ);
|
|
1884
|
-
const resolveAuthContext = async (req) => {
|
|
1885
|
-
if (!engine.studioAuthDisabled && req.headers["x-auth-scheme"] === "langsmith") {
|
|
1886
|
-
return { user: STUDIO_USER, scopes: [] };
|
|
1887
|
-
}
|
|
1888
|
-
return engine.authenticate(synthesizeRequest(req));
|
|
1889
|
-
};
|
|
1890
1986
|
const wrapped = {};
|
|
1891
1987
|
for (const name of names) {
|
|
1892
1988
|
const route = ROUTE_AUTHZ[name];
|
|
1893
1989
|
wrapped[name] = async (req) => {
|
|
1894
|
-
const authContext = await resolveAuthContext(req);
|
|
1990
|
+
const authContext = await resolveAuthContext(engine, req);
|
|
1895
1991
|
const { filters } = await engine.authorize({
|
|
1896
1992
|
resource: route.resource,
|
|
1897
1993
|
action: route.action,
|
|
@@ -2018,6 +2114,12 @@ var skeinRoutes = [
|
|
|
2018
2114
|
{ method: "patch", path: "/threads/:thread_id", handler: "patchThread" },
|
|
2019
2115
|
{ method: "delete", path: "/threads/:thread_id", handler: "deleteThread" },
|
|
2020
2116
|
{ method: "get", path: "/threads/:thread_id/state", handler: "getThreadState" },
|
|
2117
|
+
{ method: "post", path: "/threads/:thread_id/state", handler: "updateThreadState" },
|
|
2118
|
+
{
|
|
2119
|
+
method: "get",
|
|
2120
|
+
path: "/threads/:thread_id/state/:checkpoint_id",
|
|
2121
|
+
handler: "getThreadStateAtCheckpoint"
|
|
2122
|
+
},
|
|
2021
2123
|
{ method: "post", path: "/threads/:thread_id/history", handler: "getThreadHistory" },
|
|
2022
2124
|
// runs — the stateless handlers are reused on the thread-scoped path with the id folded in
|
|
2023
2125
|
{ method: "post", path: "/runs/wait", handler: "createWaitRun" },
|
|
@@ -2059,19 +2161,22 @@ function copyThreadIdIntoBody(request) {
|
|
|
2059
2161
|
return { ...request, body: { ...base, thread_id: threadId } };
|
|
2060
2162
|
}
|
|
2061
2163
|
var foldThreadId = copyThreadIdIntoBody;
|
|
2062
|
-
|
|
2063
|
-
binding
|
|
2064
|
-
|
|
2065
|
-
})
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2164
|
+
function createRouteMatcher(bindings) {
|
|
2165
|
+
const compiled = bindings.map((binding) => ({
|
|
2166
|
+
binding,
|
|
2167
|
+
regex: new RegExp(`^${binding.path.replace(/:(\w+)/g, "(?<$1>[^/]+)")}$`)
|
|
2168
|
+
}));
|
|
2169
|
+
return (method, pathname) => {
|
|
2170
|
+
const wanted = method.toLowerCase();
|
|
2171
|
+
for (const { binding, regex } of compiled) {
|
|
2172
|
+
if (binding.method !== wanted) continue;
|
|
2173
|
+
const match = regex.exec(pathname);
|
|
2174
|
+
if (match) return { binding, params: decodeParams(match.groups) };
|
|
2175
|
+
}
|
|
2176
|
+
return void 0;
|
|
2177
|
+
};
|
|
2074
2178
|
}
|
|
2179
|
+
var matchSkeinRoute = createRouteMatcher(skeinRoutes);
|
|
2075
2180
|
function decodeParams(groups) {
|
|
2076
2181
|
const params = {};
|
|
2077
2182
|
for (const [key, value] of Object.entries(groups ?? {})) {
|
|
@@ -2083,20 +2188,149 @@ function decodeParams(groups) {
|
|
|
2083
2188
|
}
|
|
2084
2189
|
return params;
|
|
2085
2190
|
}
|
|
2191
|
+
|
|
2192
|
+
// src/invoke/graph-invoke.ts
|
|
2193
|
+
import { randomUUID } from "crypto";
|
|
2194
|
+
import { MemorySaver } from "@langchain/langgraph";
|
|
2195
|
+
import {
|
|
2196
|
+
SkeinHttpError as SkeinHttpError10
|
|
2197
|
+
} from "@skein-js/core";
|
|
2198
|
+
import { z as z2 } from "zod";
|
|
2199
|
+
var DEFAULT_INVOKE_PREFIX = "/invoke";
|
|
2200
|
+
function graphInvokeRoutes(prefix = DEFAULT_INVOKE_PREFIX) {
|
|
2201
|
+
return [{ method: "post", path: `${normalizePrefix(prefix)}/:graph_id`, handler: "invokeGraph" }];
|
|
2202
|
+
}
|
|
2203
|
+
function normalizePrefix(prefix) {
|
|
2204
|
+
const trimmed = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
|
|
2205
|
+
return trimmed === "/" ? "" : trimmed;
|
|
2206
|
+
}
|
|
2207
|
+
function wantsEventStream(req) {
|
|
2208
|
+
return req.headers["accept"]?.includes("text/event-stream") ?? false;
|
|
2209
|
+
}
|
|
2210
|
+
function createRunSignal(timeoutMs, callerSignal) {
|
|
2211
|
+
if (timeoutMs === void 0 && !callerSignal) return { signal: void 0, dispose: () => {
|
|
2212
|
+
} };
|
|
2213
|
+
const controller = new AbortController();
|
|
2214
|
+
const timer = timeoutMs === void 0 ? void 0 : setTimeout(() => controller.abort(new Error(`Run exceeded ${timeoutMs}ms`)), timeoutMs);
|
|
2215
|
+
const onCallerAbort = () => controller.abort(callerSignal?.reason);
|
|
2216
|
+
if (callerSignal?.aborted) onCallerAbort();
|
|
2217
|
+
else callerSignal?.addEventListener("abort", onCallerAbort);
|
|
2218
|
+
return {
|
|
2219
|
+
signal: controller.signal,
|
|
2220
|
+
dispose: () => {
|
|
2221
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
2222
|
+
callerSignal?.removeEventListener("abort", onCallerAbort);
|
|
2223
|
+
}
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
var INVOKE_STREAM_MODES = [
|
|
2227
|
+
"values",
|
|
2228
|
+
"updates",
|
|
2229
|
+
"messages",
|
|
2230
|
+
"messages-tuple",
|
|
2231
|
+
"custom",
|
|
2232
|
+
"debug"
|
|
2233
|
+
];
|
|
2234
|
+
var streamModeQuerySchema = z2.array(z2.enum(INVOKE_STREAM_MODES)).min(1, "expected at least one stream mode");
|
|
2235
|
+
function streamModeFromQuery(value) {
|
|
2236
|
+
const raw = Array.isArray(value) ? value : value === void 0 ? [] : value.split(",");
|
|
2237
|
+
const modes = raw.map((mode) => mode.trim()).filter((mode) => mode.length > 0);
|
|
2238
|
+
if (modes.length === 0) return void 0;
|
|
2239
|
+
if (modes.includes("events")) {
|
|
2240
|
+
throw SkeinHttpError10.badRequest(
|
|
2241
|
+
'Stream mode "events" is not supported on the invoke surface; use the Agent Protocol run endpoints for token-level events.'
|
|
2242
|
+
);
|
|
2243
|
+
}
|
|
2244
|
+
return parse(streamModeQuerySchema, modes, "stream_mode query parameter");
|
|
2245
|
+
}
|
|
2246
|
+
function createGraphInvokeHandler(deps, options = {}) {
|
|
2247
|
+
return async (req) => {
|
|
2248
|
+
const graphId = requireParam(req.params, "graph_id");
|
|
2249
|
+
let authContext;
|
|
2250
|
+
if (deps.auth) {
|
|
2251
|
+
authContext = await resolveAuthContext(deps.auth, req);
|
|
2252
|
+
await deps.auth.authorize({
|
|
2253
|
+
resource: "threads",
|
|
2254
|
+
action: "create_run",
|
|
2255
|
+
// `authValue` spreads the body last, and on this surface the body is arbitrary caller-supplied
|
|
2256
|
+
// graph input — so a body key named `graph_id` would shadow the path param and let a policy
|
|
2257
|
+
// authorize a different graph than the one that actually runs. Re-stamp the server-derived id
|
|
2258
|
+
// last so the value a policy judges is always the graph we execute.
|
|
2259
|
+
value: { ...authValue(req), graph_id: graphId },
|
|
2260
|
+
context: authContext
|
|
2261
|
+
});
|
|
2262
|
+
}
|
|
2263
|
+
if (!deps.graphs.ids.includes(graphId)) {
|
|
2264
|
+
throw SkeinHttpError10.notFound(`Graph "${graphId}" is not registered.`, {
|
|
2265
|
+
code: "graph_not_found"
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2268
|
+
const factoryConfigurable2 = withAuthUser({}, authContext?.user, authContext?.scopes);
|
|
2269
|
+
const graph = await resolveCompiledGraph(deps.graphs, graphId, {
|
|
2270
|
+
configurable: Object.keys(factoryConfigurable2).length > 0 ? factoryConfigurable2 : void 0,
|
|
2271
|
+
checkpointer: new MemorySaver(),
|
|
2272
|
+
store: deps.store.store
|
|
2273
|
+
});
|
|
2274
|
+
const configurable = withAuthUser(
|
|
2275
|
+
{ thread_id: randomUUID() },
|
|
2276
|
+
authContext?.user,
|
|
2277
|
+
authContext?.scopes
|
|
2278
|
+
);
|
|
2279
|
+
const input = req.body ?? {};
|
|
2280
|
+
const { signal, dispose } = createRunSignal(deps.runTimeoutMs, req.signal);
|
|
2281
|
+
if (!wantsEventStream(req)) {
|
|
2282
|
+
try {
|
|
2283
|
+
const output = await graph.invoke(input, { configurable, signal });
|
|
2284
|
+
return { kind: "json", status: 200, body: output };
|
|
2285
|
+
} finally {
|
|
2286
|
+
dispose();
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
const streamMode = toGraphStreamModes(
|
|
2290
|
+
streamModeFromQuery(req.query["stream_mode"]) ?? options.streamMode ?? "values"
|
|
2291
|
+
);
|
|
2292
|
+
let status = "success";
|
|
2293
|
+
const frames = async function* () {
|
|
2294
|
+
let seq = 0;
|
|
2295
|
+
try {
|
|
2296
|
+
const stream = await graph.stream(input, {
|
|
2297
|
+
configurable,
|
|
2298
|
+
streamMode,
|
|
2299
|
+
signal
|
|
2300
|
+
});
|
|
2301
|
+
for await (const chunk of stream) {
|
|
2302
|
+
seq += 1;
|
|
2303
|
+
yield toRunFrame(seq, chunkToFrameBody(chunk));
|
|
2304
|
+
}
|
|
2305
|
+
} catch (error) {
|
|
2306
|
+
status = "error";
|
|
2307
|
+
seq += 1;
|
|
2308
|
+
yield { seq, event: "error", data: serializeError(error) };
|
|
2309
|
+
} finally {
|
|
2310
|
+
dispose();
|
|
2311
|
+
}
|
|
2312
|
+
};
|
|
2313
|
+
return { kind: "sse", status: 200, events: toSseEvents(frames(), async () => status) };
|
|
2314
|
+
};
|
|
2315
|
+
}
|
|
2086
2316
|
export {
|
|
2317
|
+
DEFAULT_INVOKE_PREFIX,
|
|
2087
2318
|
SSE_HEADERS,
|
|
2088
2319
|
SkeinBaseStore,
|
|
2089
2320
|
buildProtocolService,
|
|
2090
2321
|
copyThreadIdIntoBody,
|
|
2091
2322
|
createContext,
|
|
2323
|
+
createGraphInvokeHandler,
|
|
2092
2324
|
createProtocolHandlers,
|
|
2093
2325
|
createProtocolRuntime,
|
|
2094
2326
|
createProtocolService,
|
|
2095
2327
|
createProtocolServiceFromContext,
|
|
2328
|
+
createRouteMatcher,
|
|
2096
2329
|
createRunWorker,
|
|
2097
2330
|
encodeFrame,
|
|
2098
2331
|
encodeTerminal,
|
|
2099
2332
|
foldThreadId,
|
|
2333
|
+
graphInvokeRoutes,
|
|
2100
2334
|
matchSkeinRoute,
|
|
2101
2335
|
parseAfterSeq,
|
|
2102
2336
|
skeinRoutes,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skein-js/agent-protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Framework-agnostic Agent Protocol engine for LangGraph.js — run engine, handlers, and SSE, driven entirely by injected dependencies.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Maina Wycliffe <wmmaina7@gmail.com>",
|
|
@@ -44,14 +44,14 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"zod": "^3.25.76",
|
|
47
|
-
"@skein-js/core": "0.
|
|
47
|
+
"@skein-js/core": "0.9.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@langchain/langgraph": "^1.4.0",
|
|
51
51
|
"@langchain/langgraph-sdk": "^1.9.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@skein-js/storage-memory": "0.
|
|
54
|
+
"@skein-js/storage-memory": "0.9.0"
|
|
55
55
|
},
|
|
56
56
|
"publishConfig": {
|
|
57
57
|
"access": "public"
|