@skein-js/agent-protocol 0.4.0 → 0.6.3
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 +190 -44
- package/dist/index.js +686 -113
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GraphSchema, SkeinStore, RunQueue, RunEventBus, AuthEngine, Assistant, Config, StreamMode,
|
|
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';
|
|
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. */
|
|
@@ -23,6 +23,18 @@ interface GraphResolver {
|
|
|
23
23
|
}
|
|
24
24
|
/** A source of the current time; injected so tests are deterministic. */
|
|
25
25
|
type Clock = () => Date;
|
|
26
|
+
/**
|
|
27
|
+
* Delivers a run-completion webhook: POST `payload` (as JSON) to `url`. Injected so the transport is
|
|
28
|
+
* swappable and tests can capture deliveries without a network. Should resolve once sent and reject
|
|
29
|
+
* on failure — the engine calls it best-effort (a rejection is logged, never fails the run).
|
|
30
|
+
*
|
|
31
|
+
* Security: `url` is client-supplied, so the dispatcher makes a *server-side* request to a target the
|
|
32
|
+
* caller chose (an SSRF surface) and sends it the run's final `values`. The default dispatcher
|
|
33
|
+
* restricts the scheme to `http(s)` but, since skein is self-hosted and internal webhook targets are a
|
|
34
|
+
* legitimate use, does **not** block private/loopback hosts. Deployments that accept untrusted
|
|
35
|
+
* `webhook` URLs should inject a dispatcher that validates the resolved host against an allowlist.
|
|
36
|
+
*/
|
|
37
|
+
type WebhookDispatcher = (url: string, payload: unknown) => Promise<void>;
|
|
26
38
|
/** A minimal structured logger. Defaults to a no-op so nothing is required. */
|
|
27
39
|
interface Logger {
|
|
28
40
|
debug(message: string, meta?: unknown): void;
|
|
@@ -58,6 +70,11 @@ interface ProtocolDeps {
|
|
|
58
70
|
logRunActivity?: boolean;
|
|
59
71
|
/** Optional per-run wall-clock timeout in ms. When set, a run exceeding it becomes `"timeout"`. */
|
|
60
72
|
runTimeoutMs?: number;
|
|
73
|
+
/**
|
|
74
|
+
* Delivers run-completion webhooks (the run's `webhook` field). Defaults to a `globalThis.fetch`
|
|
75
|
+
* POST with a JSON body; inject to customize transport/retries or to capture deliveries in tests.
|
|
76
|
+
*/
|
|
77
|
+
webhookDispatcher?: WebhookDispatcher;
|
|
61
78
|
/**
|
|
62
79
|
* Optional auth engine. When set, every request is authenticated (401 on failure) and authorized
|
|
63
80
|
* per resource + action (403 on deny), with ownership filters scoping reads and stamping writes.
|
|
@@ -65,28 +82,23 @@ interface ProtocolDeps {
|
|
|
65
82
|
*/
|
|
66
83
|
auth?: AuthEngine;
|
|
67
84
|
}
|
|
68
|
-
/** Fill in the optional deps (`clock`, `logger`) so the rest
|
|
85
|
+
/** Fill in the optional deps (`clock`, `logger`, `webhookDispatcher`) so the rest can rely on them. */
|
|
69
86
|
interface ResolvedDeps extends ProtocolDeps {
|
|
70
87
|
clock: Clock;
|
|
71
88
|
logger: Logger;
|
|
89
|
+
webhookDispatcher: WebhookDispatcher;
|
|
72
90
|
}
|
|
73
91
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
search(query: AssistantSearch): Promise<Assistant[]>;
|
|
85
|
-
schemas(assistantId: string): Promise<GraphSchemas>;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** Why a run was aborted. Absent (`null`) means the run failed on its own. */
|
|
89
|
-
type AbortReason = "cancel" | "timeout";
|
|
92
|
+
/**
|
|
93
|
+
* Why a run was aborted. Absent (`null`) means the run failed on its own.
|
|
94
|
+
* - `cancel` — explicit `POST /runs/{id}/cancel`; the run settles `cancelled`.
|
|
95
|
+
* - `timeout` — the run exceeded `runTimeoutMs`; it settles `timeout`.
|
|
96
|
+
* - `interrupt` — displaced by a `multitask_strategy: "interrupt"` run; it settles `interrupted`,
|
|
97
|
+
* keeping its checkpoint writes.
|
|
98
|
+
* - `rollback` — displaced by a `multitask_strategy: "rollback"` run; it settles terminally and the
|
|
99
|
+
* displacing run then discards its checkpoint writes (see the run service).
|
|
100
|
+
*/
|
|
101
|
+
type AbortReason = "cancel" | "timeout" | "interrupt" | "rollback";
|
|
90
102
|
/** Handle handed to the engine for a run: the signal to thread into the graph, and the reason box. */
|
|
91
103
|
interface RunControl {
|
|
92
104
|
signal: AbortSignal;
|
|
@@ -115,13 +127,126 @@ declare class ThreadLocks {
|
|
|
115
127
|
run<T>(key: string, task: () => Promise<T>): Promise<T>;
|
|
116
128
|
}
|
|
117
129
|
|
|
130
|
+
/**
|
|
131
|
+
* What a `multitask_strategy: "rollback"` run must do to the thread *before* it executes: drop the
|
|
132
|
+
* displaced run(s)' checkpoint writes and delete their run rows. Registered at create time and
|
|
133
|
+
* applied once the displaced run has settled (see `startRunExecution`). In-process, like
|
|
134
|
+
* {@link RunControlRegistry} — a single-process seam.
|
|
135
|
+
*
|
|
136
|
+
* `revertToCheckpoint` is `false` when no displaced run wrote checkpoints (all were still pending),
|
|
137
|
+
* so only the rows are deleted; otherwise it carries the base tip to revert to (`baseCheckpointId
|
|
138
|
+
* === undefined` means the displaced run started on a fresh thread, so the revert is a clean wipe).
|
|
139
|
+
*/
|
|
140
|
+
interface RollbackPlan {
|
|
141
|
+
revertToCheckpoint: {
|
|
142
|
+
baseCheckpointId: string | undefined;
|
|
143
|
+
} | false;
|
|
144
|
+
displacedRunIds: string[];
|
|
145
|
+
}
|
|
118
146
|
interface ProtocolContext {
|
|
119
147
|
deps: ResolvedDeps;
|
|
120
148
|
control: RunControlRegistry;
|
|
149
|
+
/** Per-thread lock closing the create-guard's check-then-insert race. */
|
|
121
150
|
locks: ThreadLocks;
|
|
151
|
+
/**
|
|
152
|
+
* Per-thread lock serializing run *execution* (distinct from {@link locks}, which only guards
|
|
153
|
+
* creation). Every run executes inside it, so a second run on a busy thread waits its turn — this
|
|
154
|
+
* is what makes `multitask_strategy: "enqueue"` run behind the active run, and what makes an
|
|
155
|
+
* `interrupt`/`rollback` run start only after the displaced run has fully settled.
|
|
156
|
+
*/
|
|
157
|
+
executionLocks: ThreadLocks;
|
|
158
|
+
/**
|
|
159
|
+
* runId → the thread's checkpoint tip when that run started executing (`undefined` if the thread
|
|
160
|
+
* had no checkpoints yet). Captured by the engine at `pending -> running`, cleared when the run
|
|
161
|
+
* settles; read to compute a {@link RollbackPlan}. In-process, per {@link control}'s convention.
|
|
162
|
+
*/
|
|
163
|
+
runBaseCheckpoints: Map<string, string | undefined>;
|
|
164
|
+
/** New runId → the {@link RollbackPlan} its execution must apply before running. In-process. */
|
|
165
|
+
rollbackPlans: Map<string, RollbackPlan>;
|
|
166
|
+
/**
|
|
167
|
+
* The authenticated caller for the current request, populated by the authorizing handler wrapper
|
|
168
|
+
* so the run service can stamp it onto a run's kwargs. Undefined when no auth engine is
|
|
169
|
+
* configured (the default), matching `langgraph dev` — no principal is injected into the graph.
|
|
170
|
+
*/
|
|
171
|
+
authUser?: AuthUser;
|
|
172
|
+
/** The current request's authenticated permission scopes (`AuthContext.scopes`), stamped with {@link authUser}. */
|
|
173
|
+
authScopes?: string[];
|
|
122
174
|
}
|
|
123
175
|
declare function createContext(deps: ProtocolDeps): ProtocolContext;
|
|
124
176
|
|
|
177
|
+
interface CreateThreadInput {
|
|
178
|
+
thread_id?: string;
|
|
179
|
+
metadata?: Metadata;
|
|
180
|
+
}
|
|
181
|
+
interface PatchThreadInput {
|
|
182
|
+
metadata?: Metadata;
|
|
183
|
+
}
|
|
184
|
+
interface HistoryOptions {
|
|
185
|
+
limit?: number;
|
|
186
|
+
}
|
|
187
|
+
interface ThreadService {
|
|
188
|
+
create(input?: CreateThreadInput): Promise<Thread>;
|
|
189
|
+
get(threadId: string): Promise<Thread>;
|
|
190
|
+
list(): Promise<Thread[]>;
|
|
191
|
+
/** Filtered + paginated listing — `POST /threads/search`. */
|
|
192
|
+
search(query: ThreadSearchQuery): Promise<Thread[]>;
|
|
193
|
+
patch(threadId: string, patch: PatchThreadInput): Promise<Thread>;
|
|
194
|
+
/** Duplicate a thread (new id) together with its full checkpoint history — `POST /threads/{id}/copy`. */
|
|
195
|
+
copy(threadId: string): Promise<Thread>;
|
|
196
|
+
delete(threadId: string): Promise<void>;
|
|
197
|
+
history(threadId: string, options?: HistoryOptions): Promise<ThreadState[]>;
|
|
198
|
+
/** The thread's current state snapshot — `GET /threads/{id}/state`, what `useStream` hydrates from. */
|
|
199
|
+
getState(threadId: string): Promise<ThreadState>;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** `POST /assistants` — create input plus LangGraph's `if_exists` conflict policy. */
|
|
203
|
+
interface CreateAssistantInput extends AssistantCreate {
|
|
204
|
+
/** When the `assistant_id` already exists: `"raise"` (default, 409) or `"do_nothing"` (return it). */
|
|
205
|
+
ifExists?: "raise" | "do_nothing";
|
|
206
|
+
}
|
|
207
|
+
/** `DELETE /assistants/{id}` options. */
|
|
208
|
+
interface DeleteAssistantOptions {
|
|
209
|
+
/** Also delete threads whose `metadata.assistant_id` is this assistant (aborting their runs). */
|
|
210
|
+
deleteThreads?: boolean;
|
|
211
|
+
}
|
|
212
|
+
/** `GET /assistants/{id}/graph` options. */
|
|
213
|
+
interface DrawGraphOptions {
|
|
214
|
+
/** Include subgraphs in the drawn graph; an integer bounds the depth (mirrors LangGraph). */
|
|
215
|
+
xray?: number | boolean;
|
|
216
|
+
}
|
|
217
|
+
/** `GET /assistants/{id}/subgraphs[/{namespace}]` options. */
|
|
218
|
+
interface SubgraphsOptions {
|
|
219
|
+
/** Restrict to this subgraph namespace. */
|
|
220
|
+
namespace?: string;
|
|
221
|
+
/** Recurse into nested subgraphs. */
|
|
222
|
+
recurse?: boolean;
|
|
223
|
+
}
|
|
224
|
+
interface AssistantService {
|
|
225
|
+
/** Register one assistant per declared graph (idempotent — safe to call on every boot). */
|
|
226
|
+
registerGraphAssistants(): Promise<Assistant[]>;
|
|
227
|
+
get(assistantId: string): Promise<Assistant>;
|
|
228
|
+
list(): Promise<Assistant[]>;
|
|
229
|
+
/** Filtered + paginated listing — `POST /assistants/search`. */
|
|
230
|
+
search(query: AssistantSearchQuery): Promise<Assistant[]>;
|
|
231
|
+
/** Count matching assistants (ignores limit/offset) — `POST /assistants/count`. */
|
|
232
|
+
count(query: AssistantSearchQuery): Promise<number>;
|
|
233
|
+
schemas(assistantId: string): Promise<GraphSchemas>;
|
|
234
|
+
/** Create an assistant, honoring `if_exists` — `POST /assistants`. */
|
|
235
|
+
create(input: CreateAssistantInput): Promise<Assistant>;
|
|
236
|
+
/** Patch an assistant, minting a new version — `PATCH /assistants/{id}`. */
|
|
237
|
+
update(assistantId: string, patch: AssistantUpdate): Promise<Assistant>;
|
|
238
|
+
/** Delete an assistant (and, optionally, its threads) — `DELETE /assistants/{id}`. */
|
|
239
|
+
delete(assistantId: string, options?: DeleteAssistantOptions): Promise<void>;
|
|
240
|
+
/** Version history, newest-first — `POST /assistants/{id}/versions`. */
|
|
241
|
+
listVersions(assistantId: string, query?: AssistantVersionsQuery): Promise<AssistantVersion[]>;
|
|
242
|
+
/** Roll back to an existing version — `POST /assistants/{id}/latest`. */
|
|
243
|
+
setLatest(assistantId: string, version: number): Promise<Assistant>;
|
|
244
|
+
/** The drawable graph JSON — `GET /assistants/{id}/graph`. */
|
|
245
|
+
drawGraph(assistantId: string, options?: DrawGraphOptions): Promise<AssistantGraph>;
|
|
246
|
+
/** Each subgraph's schema, keyed by namespace — `GET /assistants/{id}/subgraphs`. */
|
|
247
|
+
subgraphs(assistantId: string, options?: SubgraphsOptions): Promise<GraphSchemas>;
|
|
248
|
+
}
|
|
249
|
+
|
|
125
250
|
/** A run request as it arrives from any of the run endpoints (already validated). */
|
|
126
251
|
interface CreateRunInput {
|
|
127
252
|
thread_id?: string;
|
|
@@ -139,6 +264,8 @@ interface CreateRunInput {
|
|
|
139
264
|
multitask_strategy?: MultitaskStrategy;
|
|
140
265
|
interrupt_before?: string[] | "*";
|
|
141
266
|
interrupt_after?: string[] | "*";
|
|
267
|
+
/** Absolute `http(s)` URL POSTed with the settled run once it reaches a terminal status. */
|
|
268
|
+
webhook?: string;
|
|
142
269
|
}
|
|
143
270
|
/** A started streaming run: its id, plus the live frame iterable to serialize as SSE. */
|
|
144
271
|
interface StartedStream {
|
|
@@ -166,31 +293,6 @@ interface StoreService {
|
|
|
166
293
|
listNamespaces(prefix?: string[]): Promise<string[][]>;
|
|
167
294
|
}
|
|
168
295
|
|
|
169
|
-
interface CreateThreadInput {
|
|
170
|
-
thread_id?: string;
|
|
171
|
-
metadata?: Metadata;
|
|
172
|
-
}
|
|
173
|
-
interface PatchThreadInput {
|
|
174
|
-
metadata?: Metadata;
|
|
175
|
-
}
|
|
176
|
-
interface HistoryOptions {
|
|
177
|
-
limit?: number;
|
|
178
|
-
}
|
|
179
|
-
interface ThreadService {
|
|
180
|
-
create(input?: CreateThreadInput): Promise<Thread>;
|
|
181
|
-
get(threadId: string): Promise<Thread>;
|
|
182
|
-
list(): Promise<Thread[]>;
|
|
183
|
-
/** Filtered + paginated listing — `POST /threads/search`. */
|
|
184
|
-
search(query: ThreadSearchQuery): Promise<Thread[]>;
|
|
185
|
-
patch(threadId: string, patch: PatchThreadInput): Promise<Thread>;
|
|
186
|
-
/** Duplicate a thread (new id) together with its full checkpoint history — `POST /threads/{id}/copy`. */
|
|
187
|
-
copy(threadId: string): Promise<Thread>;
|
|
188
|
-
delete(threadId: string): Promise<void>;
|
|
189
|
-
history(threadId: string, options?: HistoryOptions): Promise<ThreadState[]>;
|
|
190
|
-
/** The thread's current state snapshot — `GET /threads/{id}/state`, what `useStream` hydrates from. */
|
|
191
|
-
getState(threadId: string): Promise<ThreadState>;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
296
|
/** Body for `POST /threads/{id}/stream` — a run request without the thread id (it's in the path). */
|
|
195
297
|
interface ThreadStreamInput {
|
|
196
298
|
assistant_id: string;
|
|
@@ -262,7 +364,15 @@ type ProtocolHandler = (req: ProtocolRequest) => Promise<ProtocolResponse>;
|
|
|
262
364
|
interface ProtocolHandlers {
|
|
263
365
|
getAssistant: ProtocolHandler;
|
|
264
366
|
searchAssistants: ProtocolHandler;
|
|
367
|
+
countAssistants: ProtocolHandler;
|
|
265
368
|
getAssistantSchemas: ProtocolHandler;
|
|
369
|
+
createAssistant: ProtocolHandler;
|
|
370
|
+
updateAssistant: ProtocolHandler;
|
|
371
|
+
deleteAssistant: ProtocolHandler;
|
|
372
|
+
listAssistantVersions: ProtocolHandler;
|
|
373
|
+
setAssistantLatestVersion: ProtocolHandler;
|
|
374
|
+
getAssistantGraph: ProtocolHandler;
|
|
375
|
+
getAssistantSubgraphs: ProtocolHandler;
|
|
266
376
|
createThread: ProtocolHandler;
|
|
267
377
|
getThread: ProtocolHandler;
|
|
268
378
|
listThreads: ProtocolHandler;
|
|
@@ -319,6 +429,42 @@ interface ProtocolRuntime {
|
|
|
319
429
|
*/
|
|
320
430
|
declare function createProtocolRuntime(deps: ProtocolDeps, options?: ProtocolRuntimeOptions): ProtocolRuntime;
|
|
321
431
|
|
|
432
|
+
type HttpMethod = "get" | "post" | "put" | "patch" | "delete";
|
|
433
|
+
interface RouteBinding {
|
|
434
|
+
method: HttpMethod;
|
|
435
|
+
/** Path with `:param` placeholders, e.g. `/threads/:thread_id/runs/stream`. */
|
|
436
|
+
path: string;
|
|
437
|
+
handler: keyof ProtocolHandlers;
|
|
438
|
+
/**
|
|
439
|
+
* Fold the path `thread_id` into the request body before dispatch. The SDK addresses a
|
|
440
|
+
* thread-scoped run by its path (`POST /threads/{id}/runs/stream`) while carrying only
|
|
441
|
+
* `assistant_id` in the body, but the stateless run handlers read `thread_id` from the body — so a
|
|
442
|
+
* thread-scoped mount must copy it across, or the run would target a stray new thread.
|
|
443
|
+
*/
|
|
444
|
+
foldThreadIdIntoBody?: boolean;
|
|
445
|
+
}
|
|
446
|
+
/** The route table, ordered most-specific-first within each method so literals win over params. */
|
|
447
|
+
declare const skeinRoutes: readonly RouteBinding[];
|
|
448
|
+
/**
|
|
449
|
+
* Copy the path `thread_id` into an object body so a stateless run handler runs on the right thread.
|
|
450
|
+
* A no-op when there is no `thread_id` param. Used by every adapter for the `foldThreadIdIntoBody`
|
|
451
|
+
* routes, so the folding rule lives in one place.
|
|
452
|
+
*/
|
|
453
|
+
declare function foldThreadId(request: ProtocolRequest): ProtocolRequest;
|
|
454
|
+
/** A resolved route: the matched binding plus the path params extracted from the URL. */
|
|
455
|
+
interface RouteMatch {
|
|
456
|
+
binding: RouteBinding;
|
|
457
|
+
params: Record<string, string>;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Match a `method` + `pathname` (no query string) against the route table, returning the binding and
|
|
461
|
+
* extracted path params, or `undefined` when nothing matches. Iterates in table order, which is
|
|
462
|
+
* most-specific-first, so a literal segment wins over a `:param`. This is what adapters that dispatch
|
|
463
|
+
* from a catch-all route (NestJS middleware, Next.js route handlers) use in place of a framework
|
|
464
|
+
* router; Express/Fastify bind `skeinRoutes` to their native router instead.
|
|
465
|
+
*/
|
|
466
|
+
declare function matchSkeinRoute(method: string, pathname: string): RouteMatch | undefined;
|
|
467
|
+
|
|
322
468
|
type LangGraphSearchItem = Item$1 & {
|
|
323
469
|
score?: number;
|
|
324
470
|
};
|
|
@@ -372,4 +518,4 @@ declare function toSseEvents(frames: AsyncIterable<RunFrame>, finalStatus: () =>
|
|
|
372
518
|
*/
|
|
373
519
|
declare function parseAfterSeq(lastEventId: string | undefined): number;
|
|
374
520
|
|
|
375
|
-
export { type
|
|
521
|
+
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, createContext, createProtocolHandlers, createProtocolRuntime, createProtocolService, createRunWorker, encodeFrame, encodeTerminal, foldThreadId, matchSkeinRoute, parseAfterSeq, skeinRoutes, toSseEvents };
|