@skein-js/core 0.3.0 → 0.5.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 CHANGED
@@ -1,8 +1,71 @@
1
- import { Run, Config, Metadata, Assistant, StreamMode, Thread, ThreadStatus, DefaultValues, Interrupt, Item, SearchItem } from '@langchain/langgraph-sdk';
2
- export { Assistant, AssistantBase, AssistantGraph, Checkpoint, Config, DefaultValues, GraphSchema, Interrupt, Item, Metadata, Run, SearchItem, StreamMode, Thread, ThreadState, ThreadStatus, ThreadTask } from '@langchain/langgraph-sdk';
1
+ import { Run as Run$1, Config, Metadata, Assistant, StreamMode, Thread, DefaultValues, ThreadStatus, Interrupt, Item, SearchItem } from '@langchain/langgraph-sdk';
2
+ export { Assistant, AssistantBase, AssistantGraph, Checkpoint, Config, DefaultValues, GraphSchema, Interrupt, Item, Metadata, SearchItem, StreamMode, Thread, ThreadState, ThreadStatus, ThreadTask } from '@langchain/langgraph-sdk';
3
3
 
4
- type RunStatus = Run["status"];
5
- type MultitaskStrategy = NonNullable<Run["multitask_strategy"]>;
4
+ type RunStatus = Run$1["status"] | "cancelled";
5
+ type Run = Omit<Run$1, "status"> & {
6
+ status: RunStatus;
7
+ };
8
+ type MultitaskStrategy = NonNullable<Run$1["multitask_strategy"]>;
9
+
10
+ /**
11
+ * The authenticated caller, normalized to the shape LangGraph's `Auth` produces: a required
12
+ * `identity`, `display_name`, `is_authenticated`, and `permissions` scopes, plus open extra keys a
13
+ * handler may attach (e.g. `email`, `org_id`). Structurally identical to the SDK's internal
14
+ * `BaseUser`, so a graph written for LangGraph Platform reads the same `langgraph_auth_user`.
15
+ */
16
+ interface AuthUser {
17
+ identity: string;
18
+ display_name: string;
19
+ is_authenticated: boolean;
20
+ permissions: string[];
21
+ [key: string]: unknown;
22
+ }
23
+ /** The result of authenticating a request: the caller plus their permission scopes. */
24
+ interface AuthContext {
25
+ user: AuthUser;
26
+ scopes: string[];
27
+ }
28
+ /** A protocol resource an `@auth.on.*` handler can guard. Runs authorize through their thread. */
29
+ type AuthResource = "threads" | "assistants" | "store";
30
+ /** An action on a resource, mirroring LangGraph's `resource:action` event names. */
31
+ type AuthAction = "create" | "read" | "update" | "delete" | "search" | "create_run" | "put" | "get" | "list_namespaces";
32
+ /** A single metadata filter clause — an exact value or an `$eq`/`$contains` operator object. */
33
+ type AuthFilterValue = string | {
34
+ $eq?: string;
35
+ $contains?: string | string[];
36
+ };
37
+ /**
38
+ * Ownership filters returned by an `@auth.on.*` handler. Keys are metadata fields; a returned filter
39
+ * both scopes reads (a resource is visible only if its metadata satisfies every clause) and stamps
40
+ * writes (the clause values are merged into new resources' metadata). Shape-compatible with
41
+ * `@langchain/langgraph-api`'s `isAuthMatching`.
42
+ */
43
+ type AuthFilters = Record<string, AuthFilterValue>;
44
+ /**
45
+ * The injectable auth engine — one per runtime, no module-global state (unlike langgraph-api's
46
+ * `registerAuth`). Absent from `ProtocolDeps` means no auth is configured and every request is
47
+ * allowed (the default, so `skein dev` stays frictionless).
48
+ */
49
+ interface AuthEngine {
50
+ /** True when a `langgraph.json` `auth.path` was loaded; false disables the whole gate. */
51
+ readonly enabled: boolean;
52
+ /** When true, studio traffic must present real credentials like any other client. */
53
+ readonly studioAuthDisabled: boolean;
54
+ /** Run the user's authenticate handler over a request; throws 401 on rejection/missing identity. */
55
+ authenticate(request: Request): Promise<AuthContext | undefined>;
56
+ /** Consult the `@auth.on.*` handlers for a resource+action; throws 403 on deny, else returns filters. */
57
+ authorize(input: {
58
+ resource: AuthResource;
59
+ action: AuthAction;
60
+ value: unknown;
61
+ context: AuthContext | undefined;
62
+ }): Promise<{
63
+ filters?: AuthFilters;
64
+ value: unknown;
65
+ }>;
66
+ /** Whether a resource's metadata satisfies the ownership filters (`$eq`/`$contains` semantics). */
67
+ matchesFilters(metadata: Record<string, unknown> | undefined, filters?: AuthFilters): boolean;
68
+ }
6
69
 
7
70
  /** Fields accepted when registering an assistant (from a langgraph.json graph or the API). */
8
71
  interface AssistantCreate {
@@ -37,13 +100,42 @@ interface ThreadUpdate {
37
100
  /** Pending human-in-the-loop interrupts, mirrored from the graph state onto the thread row. */
38
101
  interrupts?: Record<string, Interrupt[]>;
39
102
  }
103
+ /** Filter + pagination for `POST /threads/search`. Omitted fields don't constrain the result. */
104
+ interface ThreadSearchQuery {
105
+ /** Match threads whose metadata contains every one of these key/value pairs (subset match). */
106
+ metadata?: Metadata;
107
+ /** Match threads whose mirrored graph values contain every one of these key/value pairs. */
108
+ values?: DefaultValues;
109
+ /** Restrict to threads in this status. */
110
+ status?: ThreadStatus;
111
+ /** Restrict to these thread ids. */
112
+ ids?: string[];
113
+ limit?: number;
114
+ offset?: number;
115
+ /** Sort key; defaults to `created_at`. */
116
+ sortBy?: "thread_id" | "status" | "created_at" | "updated_at";
117
+ /** Sort direction; defaults to `desc`. */
118
+ sortOrder?: "asc" | "desc";
119
+ }
40
120
  interface ThreadRepo {
41
121
  list(): Promise<Thread[]>;
122
+ /** Filtered + paginated listing backing `POST /threads/search`. */
123
+ search(query: ThreadSearchQuery): Promise<Thread[]>;
42
124
  get(threadId: string): Promise<Thread | null>;
43
125
  create(input?: ThreadCreate): Promise<Thread>;
44
126
  update(threadId: string, patch: ThreadUpdate): Promise<Thread>;
127
+ /** Duplicate a thread's row (new id, fresh timestamps); checkpoint history is copied at the service layer. */
128
+ copy(threadId: string): Promise<Thread>;
45
129
  delete(threadId: string): Promise<void>;
46
130
  }
131
+ /**
132
+ * True if `subject` contains `filter`, mirroring Postgres' JSONB `@>` operator so the memory driver,
133
+ * the conformance suite, and the Postgres driver all agree on metadata/values matching. Containment is
134
+ * recursive: an object matches on a *subset* of its keys (nested objects included), an array matches as
135
+ * a set (every filter element is contained in some subject element), and scalars match by equality. An
136
+ * empty (or absent) filter matches everything.
137
+ */
138
+ declare function isMetadataSubset(subject: unknown, filter: unknown): boolean;
47
139
  /**
48
140
  * The execution payload of a run — everything the run engine needs to (re)start a graph. Stored
49
141
  * *opaquely* alongside the run (it is NOT part of the wire {@link Run}), so a background run picked
@@ -64,6 +156,18 @@ interface RunKwargs {
64
156
  stream_mode?: StreamMode | StreamMode[];
65
157
  interrupt_before?: string[] | "*";
66
158
  interrupt_after?: string[] | "*";
159
+ /**
160
+ * The authenticated caller, stamped by the server (never accepted from the client). Persisted
161
+ * opaquely with the run so a background/crash-recovered run on another instance reconstructs the
162
+ * principal via `getKwargs` and injects it into the graph's `configurable.langgraph_auth_user`.
163
+ */
164
+ auth_user?: AuthUser;
165
+ /**
166
+ * The caller's authenticated permission scopes (the `AuthContext.scopes`), stamped alongside
167
+ * {@link auth_user}. Injected as `configurable.langgraph_auth_permissions`, matching LangGraph
168
+ * (which sources permissions from the auth scopes, not from the user object's `permissions`).
169
+ */
170
+ auth_scopes?: string[];
67
171
  }
68
172
  interface RunCreate {
69
173
  thread_id: string;
@@ -109,12 +213,32 @@ interface StoreSearchQuery {
109
213
  limit?: number;
110
214
  offset?: number;
111
215
  }
216
+ /**
217
+ * Expiry policy for long-term store items (from `langgraph.json` `store.ttl`). All durations are in
218
+ * minutes. A driver applies `defaultTtl` when a `put` gives no explicit `ttl`, refreshes an item's
219
+ * expiry on read when `refreshOnRead` is set, and a background sweeper (interval `sweepIntervalMinutes`)
220
+ * deletes expired rows via {@link StoreRepo.sweepExpired}.
221
+ */
222
+ interface StoreTtlConfig {
223
+ /** Default item lifetime in minutes when `put` doesn't pass its own `ttl`. */
224
+ defaultTtl?: number;
225
+ /** Extend an item's expiry when it is read. Defaults to true. */
226
+ refreshOnRead?: boolean;
227
+ /** Sweeper cadence in minutes. Defaults to 60. */
228
+ sweepIntervalMinutes?: number;
229
+ }
230
+ /** Per-`put` options. `ttl` (minutes) overrides the configured `defaultTtl` for this item. */
231
+ interface StorePutOptions {
232
+ ttl?: number;
233
+ }
112
234
  interface StoreRepo {
113
235
  get(namespace: string[], key: string): Promise<Item | null>;
114
- put(namespace: string[], key: string, value: Record<string, unknown>): Promise<Item>;
236
+ put(namespace: string[], key: string, value: Record<string, unknown>, options?: StorePutOptions): Promise<Item>;
115
237
  delete(namespace: string[], key: string): Promise<void>;
116
238
  search(query: StoreSearchQuery): Promise<SearchItem[]>;
117
239
  listNamespaces(prefix?: string[]): Promise<string[][]>;
240
+ /** Delete every expired item; returns how many were removed. No-op when TTL is unconfigured. */
241
+ sweepExpired(): Promise<number>;
118
242
  }
119
243
  /** The single persistence seam for Agent Protocol resources. One implementation per driver. */
120
244
  interface SkeinStore {
@@ -241,62 +365,4 @@ declare class SkeinHttpError extends Error {
241
365
  /** Narrow an unknown thrown value to a {@link SkeinHttpError}. */
242
366
  declare function isSkeinHttpError(value: unknown): value is SkeinHttpError;
243
367
 
244
- /**
245
- * The authenticated caller, normalized to the shape LangGraph produces: a required `identity`,
246
- * `permissions` scopes, and open extra keys a handler may attach (e.g. `email`, `org_id`).
247
- */
248
- interface AuthUser {
249
- identity: string;
250
- display_name: string;
251
- is_authenticated: boolean;
252
- permissions: string[];
253
- [key: string]: unknown;
254
- }
255
- /** The result of authenticating a request: the caller plus their permission scopes. */
256
- interface AuthContext {
257
- user: AuthUser;
258
- scopes: string[];
259
- }
260
- /** A protocol resource an `@auth.on.*` handler can guard. Runs authorize through their thread. */
261
- type AuthResource = "threads" | "assistants" | "store";
262
- /** An action on a resource, mirroring LangGraph's `resource:action` event names. */
263
- type AuthAction = "create" | "read" | "update" | "delete" | "search" | "create_run" | "put" | "get" | "list_namespaces";
264
- /** A single metadata filter clause — an exact value or an `$eq`/`$contains` operator object. */
265
- type AuthFilterValue = string | {
266
- $eq?: string;
267
- $contains?: string | string[];
268
- };
269
- /**
270
- * Ownership filters returned by an `@auth.on.*` handler. Keys are metadata fields; a returned filter
271
- * both scopes reads (a resource is visible only if its metadata satisfies every clause) and stamps
272
- * writes (the clause values are merged into new resources' metadata). Shape-compatible with
273
- * `@langchain/langgraph-api`'s `isAuthMatching`.
274
- */
275
- type AuthFilters = Record<string, AuthFilterValue>;
276
- /**
277
- * The injectable auth engine — one per runtime, no module-global state (unlike langgraph-api's
278
- * `registerAuth`). Absent from `ProtocolDeps` means no auth is configured and every request is
279
- * allowed (the default, so `skein dev` stays frictionless).
280
- */
281
- interface AuthEngine {
282
- /** True when a `langgraph.json` `auth.path` was loaded; false disables the whole gate. */
283
- readonly enabled: boolean;
284
- /** When true, studio traffic must present real credentials like any other client. */
285
- readonly studioAuthDisabled: boolean;
286
- /** Run the user's authenticate handler over a request; throws 401 on rejection/missing identity. */
287
- authenticate(request: Request): Promise<AuthContext | undefined>;
288
- /** Consult the `@auth.on.*` handlers for a resource+action; throws 403 on deny, else returns filters. */
289
- authorize(input: {
290
- resource: AuthResource;
291
- action: AuthAction;
292
- value: unknown;
293
- context: AuthContext | undefined;
294
- }): Promise<{
295
- filters?: AuthFilters;
296
- value: unknown;
297
- }>;
298
- /** Whether a resource's metadata satisfies the ownership filters (`$eq`/`$contains` semantics). */
299
- matchesFilters(metadata: Record<string, unknown> | undefined, filters?: AuthFilters): boolean;
300
- }
301
-
302
- export { type AssistantCreate, type AssistantRepo, type AuthAction, type AuthContext, type AuthEngine, type AuthFilterValue, type AuthFilters, type AuthResource, type AuthUser, type MultitaskStrategy, type QueuedRun, type RunConsumer, type RunConsumerOptions, type RunCreate, type RunEventBus, type RunFrame, type RunKwargs, type RunProcessor, type RunQueue, type RunRepo, type RunStatus, SkeinHttpError, type SkeinHttpErrorOptions, type SkeinStore, type SkeinStoreSnapshot, type StoreRepo, type StoreSearchQuery, TERMINAL_RUN_STATUSES, type ThreadCreate, type ThreadRepo, type ThreadUpdate, isSkeinHttpError, isTerminalRunStatus, serializeWireJson };
368
+ export { type AssistantCreate, type AssistantRepo, type AuthAction, type AuthContext, type AuthEngine, type AuthFilterValue, type AuthFilters, type AuthResource, type AuthUser, type MultitaskStrategy, type QueuedRun, type Run, type RunConsumer, type RunConsumerOptions, type RunCreate, type RunEventBus, type RunFrame, type RunKwargs, type RunProcessor, type RunQueue, type RunRepo, type RunStatus, SkeinHttpError, type SkeinHttpErrorOptions, type SkeinStore, type SkeinStoreSnapshot, type StorePutOptions, type StoreRepo, type StoreSearchQuery, type StoreTtlConfig, TERMINAL_RUN_STATUSES, type ThreadCreate, type ThreadRepo, type ThreadSearchQuery, type ThreadUpdate, isMetadataSubset, isSkeinHttpError, isTerminalRunStatus, serializeWireJson };
package/dist/index.js CHANGED
@@ -1,9 +1,26 @@
1
1
  // src/store/skein-store.ts
2
+ function isMetadataSubset(subject, filter) {
3
+ if (filter === void 0 || filter === null) return true;
4
+ return jsonbContains(subject, filter);
5
+ }
6
+ function jsonbContains(subject, filter) {
7
+ if (filter === null || typeof filter !== "object") return subject === filter;
8
+ if (Array.isArray(filter)) {
9
+ if (!Array.isArray(subject)) return false;
10
+ return filter.every((wanted) => subject.some((candidate) => jsonbContains(candidate, wanted)));
11
+ }
12
+ const entries = Object.entries(filter);
13
+ if (entries.length === 0) return true;
14
+ if (subject === null || typeof subject !== "object" || Array.isArray(subject)) return false;
15
+ const row = subject;
16
+ return entries.every(([key, value]) => key in row && jsonbContains(row[key], value));
17
+ }
2
18
  var TERMINAL_RUN_STATUSES = [
3
19
  "success",
4
20
  "error",
5
21
  "timeout",
6
- "interrupted"
22
+ "interrupted",
23
+ "cancelled"
7
24
  ];
8
25
  function isTerminalRunStatus(status) {
9
26
  return TERMINAL_RUN_STATUSES.includes(status);
@@ -66,6 +83,7 @@ function isSkeinHttpError(value) {
66
83
  export {
67
84
  SkeinHttpError,
68
85
  TERMINAL_RUN_STATUSES,
86
+ isMetadataSubset,
69
87
  isSkeinHttpError,
70
88
  isTerminalRunStatus,
71
89
  serializeWireJson
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skein-js/core",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Framework-agnostic Agent Protocol engine for LangGraph.js — the heart of skein-js.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Maina Wycliffe <wmmaina7@gmail.com>",