@skein-js/agent-protocol 0.6.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts +46 -5
- package/dist/index.js +112 -13
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ Graph **state, history, and interrupt/resume are 100% LangGraph-native** via the
|
|
|
101
101
|
## API
|
|
102
102
|
|
|
103
103
|
- **Entry points:** `createProtocolRuntime(deps, options?)` → `{ service, handlers, worker }`;
|
|
104
|
-
`createProtocolService` / `
|
|
104
|
+
`createProtocolService` / `createProtocolServiceFromContext`; `createProtocolHandlers`; `createContext`;
|
|
105
105
|
`createRunWorker(ctx, options?)` (`RunWorkerOptions`: `maxConcurrency`, `shutdownGraceMs`).
|
|
106
106
|
- **Service surface** (`runtime.service`): `assistants` (`registerGraphAssistants`, `get`, `list`,
|
|
107
107
|
`search`, `schemas`), `threads` (`create`/`get`/`list`/`patch`/`delete`/`history`/`getState`),
|
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 {
|
|
@@ -331,10 +353,16 @@ interface ProtocolService {
|
|
|
331
353
|
store: StoreService;
|
|
332
354
|
}
|
|
333
355
|
/** Assemble the service over an existing context (used by the runtime to share the context). */
|
|
334
|
-
declare function
|
|
356
|
+
declare function createProtocolServiceFromContext(ctx: ProtocolContext): ProtocolService;
|
|
335
357
|
/** Build the service with its own context. Use {@link createProtocolRuntime} when you also run a
|
|
336
358
|
* background worker in the same process, so cancellation is shared. */
|
|
337
359
|
declare function createProtocolService(deps: ProtocolDeps): ProtocolService;
|
|
360
|
+
/**
|
|
361
|
+
* @deprecated Renamed to {@link createProtocolServiceFromContext} — it builds the service over an
|
|
362
|
+
* existing `ProtocolContext` (vs {@link createProtocolService}, which takes `deps` and makes its own).
|
|
363
|
+
* Kept for back-compat; slated for removal in a future major.
|
|
364
|
+
*/
|
|
365
|
+
declare const buildProtocolService: typeof createProtocolServiceFromContext;
|
|
338
366
|
|
|
339
367
|
/** A normalized request an adapter maps its framework request onto. */
|
|
340
368
|
interface ProtocolRequest {
|
|
@@ -381,6 +409,8 @@ interface ProtocolHandlers {
|
|
|
381
409
|
deleteThread: ProtocolHandler;
|
|
382
410
|
getThreadHistory: ProtocolHandler;
|
|
383
411
|
getThreadState: ProtocolHandler;
|
|
412
|
+
getThreadStateAtCheckpoint: ProtocolHandler;
|
|
413
|
+
updateThreadState: ProtocolHandler;
|
|
384
414
|
createWaitRun: ProtocolHandler;
|
|
385
415
|
createStreamRun: ProtocolHandler;
|
|
386
416
|
createBackgroundRun: ProtocolHandler;
|
|
@@ -414,12 +444,18 @@ interface RunWorker {
|
|
|
414
444
|
}
|
|
415
445
|
declare function createRunWorker(ctx: ProtocolContext, options?: RunWorkerOptions): RunWorker;
|
|
416
446
|
|
|
447
|
+
/** Options for {@link createProtocolRuntime}. */
|
|
417
448
|
interface ProtocolRuntimeOptions {
|
|
449
|
+
/** Tuning for the background run worker (concurrency, poll interval). */
|
|
418
450
|
worker?: RunWorkerOptions;
|
|
419
451
|
}
|
|
452
|
+
/** The wired engine: the service, the transport-neutral handler table, and the background worker. */
|
|
420
453
|
interface ProtocolRuntime {
|
|
454
|
+
/** High-level operations over assistants / threads / runs / store (used to seed assistants). */
|
|
421
455
|
service: ProtocolService;
|
|
456
|
+
/** The transport-neutral HTTP handler table an adapter dispatches requests into. */
|
|
422
457
|
handlers: ProtocolHandlers;
|
|
458
|
+
/** The background worker that drains the run queue; `start()` it after seeding assistants. */
|
|
423
459
|
worker: RunWorker;
|
|
424
460
|
}
|
|
425
461
|
/**
|
|
@@ -448,9 +484,14 @@ declare const skeinRoutes: readonly RouteBinding[];
|
|
|
448
484
|
/**
|
|
449
485
|
* Copy the path `thread_id` into an object body so a stateless run handler runs on the right thread.
|
|
450
486
|
* A no-op when there is no `thread_id` param. Used by every adapter for the `foldThreadIdIntoBody`
|
|
451
|
-
* routes, so
|
|
487
|
+
* routes, so this rule lives in one place.
|
|
488
|
+
*/
|
|
489
|
+
declare function copyThreadIdIntoBody(request: ProtocolRequest): ProtocolRequest;
|
|
490
|
+
/**
|
|
491
|
+
* @deprecated Renamed to {@link copyThreadIdIntoBody} — it copies the path `thread_id` into the
|
|
492
|
+
* request body. Kept for back-compat; slated for removal in a future major.
|
|
452
493
|
*/
|
|
453
|
-
declare
|
|
494
|
+
declare const foldThreadId: typeof copyThreadIdIntoBody;
|
|
454
495
|
/** A resolved route: the matched binding plus the path params extracted from the URL. */
|
|
455
496
|
interface RouteMatch {
|
|
456
497
|
binding: RouteBinding;
|
|
@@ -518,4 +559,4 @@ declare function toSseEvents(frames: AsyncIterable<RunFrame>, finalStatus: () =>
|
|
|
518
559
|
*/
|
|
519
560
|
declare function parseAfterSeq(lastEventId: string | undefined): number;
|
|
520
561
|
|
|
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 };
|
|
562
|
+
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 };
|
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) => {
|
|
@@ -990,10 +1026,15 @@ function toFactoryConfigurable(kwargs) {
|
|
|
990
1026
|
}
|
|
991
1027
|
function toGraphCallOptions(kwargs, threadId, signal) {
|
|
992
1028
|
const options = {
|
|
993
|
-
// Drop server-owned keys from the client's configurable, force this thread's id,
|
|
994
|
-
//
|
|
1029
|
+
// Drop server-owned keys from the client's configurable, force this thread's id, add the
|
|
1030
|
+
// server-owned time-travel fork target (if any) *after* sanitizing so the client can never spoof
|
|
1031
|
+
// it, then stamp the authenticated caller so the graph can authorize off `langgraph_auth_user`.
|
|
995
1032
|
configurable: withAuthUser(
|
|
996
|
-
{
|
|
1033
|
+
{
|
|
1034
|
+
...sanitizeConfigurable(kwargs.config?.configurable),
|
|
1035
|
+
thread_id: threadId,
|
|
1036
|
+
...kwargs.checkpoint_id !== void 0 ? { checkpoint_id: kwargs.checkpoint_id } : {}
|
|
1037
|
+
},
|
|
997
1038
|
kwargs.auth_user,
|
|
998
1039
|
kwargs.auth_scopes
|
|
999
1040
|
),
|
|
@@ -1334,6 +1375,7 @@ function toKwargs(input, authUser, authScopes) {
|
|
|
1334
1375
|
if (input.interrupt_before !== void 0) kwargs.interrupt_before = input.interrupt_before;
|
|
1335
1376
|
if (input.interrupt_after !== void 0) kwargs.interrupt_after = input.interrupt_after;
|
|
1336
1377
|
if (input.webhook !== void 0) kwargs.webhook = input.webhook;
|
|
1378
|
+
if (input.checkpoint_id !== void 0) kwargs.checkpoint_id = input.checkpoint_id;
|
|
1337
1379
|
if (authUser !== void 0) {
|
|
1338
1380
|
kwargs.auth_user = authUser;
|
|
1339
1381
|
if (authScopes !== void 0) kwargs.auth_scopes = authScopes;
|
|
@@ -1554,13 +1596,13 @@ function createThreadService(ctx) {
|
|
|
1554
1596
|
if (!thread) throw SkeinHttpError7.notFound(`Thread "${threadId}" not found.`);
|
|
1555
1597
|
return thread;
|
|
1556
1598
|
};
|
|
1557
|
-
const
|
|
1599
|
+
const loadThreadGraph = async (threadId) => {
|
|
1558
1600
|
await requireThread(threadId);
|
|
1559
1601
|
const runs = await deps.store.runs.listByThread(threadId);
|
|
1560
1602
|
const latest = [...runs].sort((a, b) => b.created_at.localeCompare(a.created_at))[0];
|
|
1561
|
-
if (!latest) return
|
|
1603
|
+
if (!latest) return void 0;
|
|
1562
1604
|
const assistant = await deps.store.assistants.get(latest.assistant_id);
|
|
1563
|
-
if (!assistant) return
|
|
1605
|
+
if (!assistant) return void 0;
|
|
1564
1606
|
const resolved = await deps.graphs.load(assistant.graph_id);
|
|
1565
1607
|
let graph;
|
|
1566
1608
|
if (typeof resolved === "function") {
|
|
@@ -1570,6 +1612,11 @@ function createThreadService(ctx) {
|
|
|
1570
1612
|
graph = resolved;
|
|
1571
1613
|
}
|
|
1572
1614
|
graph.checkpointer = deps.checkpointer;
|
|
1615
|
+
return graph;
|
|
1616
|
+
};
|
|
1617
|
+
const readHistory = async (threadId, options) => {
|
|
1618
|
+
const graph = await loadThreadGraph(threadId);
|
|
1619
|
+
if (!graph) return [];
|
|
1573
1620
|
const states = [];
|
|
1574
1621
|
const limit = options?.limit;
|
|
1575
1622
|
for await (const snapshot of graph.getStateHistory({
|
|
@@ -1626,6 +1673,45 @@ function createThreadService(ctx) {
|
|
|
1626
1673
|
async getState(threadId) {
|
|
1627
1674
|
const [current] = await readHistory(threadId, { limit: 1 });
|
|
1628
1675
|
return current ?? emptyThreadState(threadId);
|
|
1676
|
+
},
|
|
1677
|
+
async getStateAt(threadId, checkpointId) {
|
|
1678
|
+
const graph = await loadThreadGraph(threadId);
|
|
1679
|
+
if (!graph) return emptyThreadState(threadId);
|
|
1680
|
+
const snapshot = await graph.getState({
|
|
1681
|
+
configurable: { thread_id: threadId, checkpoint_ns: "", checkpoint_id: checkpointId }
|
|
1682
|
+
});
|
|
1683
|
+
return snapshotToThreadState(snapshot);
|
|
1684
|
+
},
|
|
1685
|
+
async updateState(threadId, input) {
|
|
1686
|
+
const graph = await loadThreadGraph(threadId);
|
|
1687
|
+
if (!graph) {
|
|
1688
|
+
throw SkeinHttpError7.unprocessable(`Thread "${threadId}" has no graph to update state on.`);
|
|
1689
|
+
}
|
|
1690
|
+
if (await deps.store.runs.hasActiveRun(threadId)) {
|
|
1691
|
+
throw SkeinHttpError7.conflict(
|
|
1692
|
+
`Thread "${threadId}" is busy; wait for its active run to finish before updating state.`
|
|
1693
|
+
);
|
|
1694
|
+
}
|
|
1695
|
+
const configurable = {
|
|
1696
|
+
checkpoint_ns: "",
|
|
1697
|
+
...input.checkpoint ?? {},
|
|
1698
|
+
...input.checkpoint_id !== void 0 ? { checkpoint_id: input.checkpoint_id } : {},
|
|
1699
|
+
thread_id: threadId
|
|
1700
|
+
};
|
|
1701
|
+
const nextConfig = await graph.updateState({ configurable }, input.values, input.as_node);
|
|
1702
|
+
const snapshot = await graph.getState({ configurable: { thread_id: threadId } });
|
|
1703
|
+
await deps.store.threads.update(
|
|
1704
|
+
threadId,
|
|
1705
|
+
snapshotToThreadUpdate(snapshot, runStatusForSnapshot(snapshot))
|
|
1706
|
+
);
|
|
1707
|
+
const next = nextConfig.configurable ?? {};
|
|
1708
|
+
const checkpoint = {
|
|
1709
|
+
thread_id: threadId,
|
|
1710
|
+
checkpoint_ns: next["checkpoint_ns"] ?? "",
|
|
1711
|
+
checkpoint_id: next["checkpoint_id"],
|
|
1712
|
+
checkpoint_map: next["checkpoint_map"]
|
|
1713
|
+
};
|
|
1714
|
+
return { checkpoint };
|
|
1629
1715
|
}
|
|
1630
1716
|
};
|
|
1631
1717
|
}
|
|
@@ -1692,7 +1778,7 @@ function createThreadStreamService(ctx, runs) {
|
|
|
1692
1778
|
}
|
|
1693
1779
|
|
|
1694
1780
|
// src/service.ts
|
|
1695
|
-
function
|
|
1781
|
+
function createProtocolServiceFromContext(ctx) {
|
|
1696
1782
|
const runs = createRunService(ctx);
|
|
1697
1783
|
const threads = createThreadService(ctx);
|
|
1698
1784
|
return {
|
|
@@ -1707,8 +1793,9 @@ function buildProtocolService(ctx) {
|
|
|
1707
1793
|
};
|
|
1708
1794
|
}
|
|
1709
1795
|
function createProtocolService(deps) {
|
|
1710
|
-
return
|
|
1796
|
+
return createProtocolServiceFromContext(createContext(deps));
|
|
1711
1797
|
}
|
|
1798
|
+
var buildProtocolService = createProtocolServiceFromContext;
|
|
1712
1799
|
|
|
1713
1800
|
// src/auth/auth-scoped-store.ts
|
|
1714
1801
|
import {
|
|
@@ -1827,9 +1914,12 @@ var ROUTE_AUTHZ = {
|
|
|
1827
1914
|
copyThread: { resource: "threads", action: "create" },
|
|
1828
1915
|
getThread: { resource: "threads", action: "read" },
|
|
1829
1916
|
getThreadState: { resource: "threads", action: "read" },
|
|
1917
|
+
getThreadStateAtCheckpoint: { resource: "threads", action: "read" },
|
|
1830
1918
|
getThreadHistory: { resource: "threads", action: "read" },
|
|
1831
1919
|
listThreads: { resource: "threads", action: "search" },
|
|
1832
1920
|
patchThread: { resource: "threads", action: "update" },
|
|
1921
|
+
// Time-travel state update forks a checkpoint — a write, so read-only principals can't fork.
|
|
1922
|
+
updateThreadState: { resource: "threads", action: "update" },
|
|
1833
1923
|
deleteThread: { resource: "threads", action: "delete" },
|
|
1834
1924
|
// runs (authorized through the owning thread)
|
|
1835
1925
|
createWaitRun: { resource: "threads", action: "create_run" },
|
|
@@ -1878,7 +1968,7 @@ var STUDIO_USER = {
|
|
|
1878
1968
|
permissions: []
|
|
1879
1969
|
};
|
|
1880
1970
|
function createAuthorizingHandlers(context, engine) {
|
|
1881
|
-
const baseHandlers = createProtocolHandlers(
|
|
1971
|
+
const baseHandlers = createProtocolHandlers(createProtocolServiceFromContext(context));
|
|
1882
1972
|
const names = Object.keys(ROUTE_AUTHZ);
|
|
1883
1973
|
const resolveAuthContext = async (req) => {
|
|
1884
1974
|
if (!engine.studioAuthDisabled && req.headers["x-auth-scheme"] === "langsmith") {
|
|
@@ -1907,7 +1997,7 @@ function createAuthorizingHandlers(context, engine) {
|
|
|
1907
1997
|
store: createAuthScopedStore(context.deps.store, engine, filters, route.resource)
|
|
1908
1998
|
} : context.deps
|
|
1909
1999
|
};
|
|
1910
|
-
return createProtocolHandlers(
|
|
2000
|
+
return createProtocolHandlers(createProtocolServiceFromContext(requestContext))[name](req);
|
|
1911
2001
|
};
|
|
1912
2002
|
}
|
|
1913
2003
|
return wrapped;
|
|
@@ -1977,7 +2067,7 @@ function createRunWorker(ctx, options = {}) {
|
|
|
1977
2067
|
// src/runtime.ts
|
|
1978
2068
|
function createProtocolRuntime(deps, options = {}) {
|
|
1979
2069
|
const context = createContext(deps);
|
|
1980
|
-
const service =
|
|
2070
|
+
const service = createProtocolServiceFromContext(context);
|
|
1981
2071
|
const handlers = deps.auth ? createAuthorizingHandlers(context, deps.auth) : createProtocolHandlers(service);
|
|
1982
2072
|
return {
|
|
1983
2073
|
service,
|
|
@@ -2017,6 +2107,12 @@ var skeinRoutes = [
|
|
|
2017
2107
|
{ method: "patch", path: "/threads/:thread_id", handler: "patchThread" },
|
|
2018
2108
|
{ method: "delete", path: "/threads/:thread_id", handler: "deleteThread" },
|
|
2019
2109
|
{ method: "get", path: "/threads/:thread_id/state", handler: "getThreadState" },
|
|
2110
|
+
{ method: "post", path: "/threads/:thread_id/state", handler: "updateThreadState" },
|
|
2111
|
+
{
|
|
2112
|
+
method: "get",
|
|
2113
|
+
path: "/threads/:thread_id/state/:checkpoint_id",
|
|
2114
|
+
handler: "getThreadStateAtCheckpoint"
|
|
2115
|
+
},
|
|
2020
2116
|
{ method: "post", path: "/threads/:thread_id/history", handler: "getThreadHistory" },
|
|
2021
2117
|
// runs — the stateless handlers are reused on the thread-scoped path with the id folded in
|
|
2022
2118
|
{ method: "post", path: "/runs/wait", handler: "createWaitRun" },
|
|
@@ -2051,12 +2147,13 @@ var skeinRoutes = [
|
|
|
2051
2147
|
{ method: "post", path: "/store/items/search", handler: "searchStoreItems" },
|
|
2052
2148
|
{ method: "post", path: "/store/namespaces", handler: "listStoreNamespaces" }
|
|
2053
2149
|
];
|
|
2054
|
-
function
|
|
2150
|
+
function copyThreadIdIntoBody(request) {
|
|
2055
2151
|
const threadId = request.params["thread_id"];
|
|
2056
2152
|
if (threadId === void 0) return request;
|
|
2057
2153
|
const base = typeof request.body === "object" && request.body !== null && !Array.isArray(request.body) ? request.body : {};
|
|
2058
2154
|
return { ...request, body: { ...base, thread_id: threadId } };
|
|
2059
2155
|
}
|
|
2156
|
+
var foldThreadId = copyThreadIdIntoBody;
|
|
2060
2157
|
var compiledRoutes = skeinRoutes.map((binding) => ({
|
|
2061
2158
|
binding,
|
|
2062
2159
|
regex: new RegExp(`^${binding.path.replace(/:(\w+)/g, "(?<$1>[^/]+)")}$`)
|
|
@@ -2085,10 +2182,12 @@ export {
|
|
|
2085
2182
|
SSE_HEADERS,
|
|
2086
2183
|
SkeinBaseStore,
|
|
2087
2184
|
buildProtocolService,
|
|
2185
|
+
copyThreadIdIntoBody,
|
|
2088
2186
|
createContext,
|
|
2089
2187
|
createProtocolHandlers,
|
|
2090
2188
|
createProtocolRuntime,
|
|
2091
2189
|
createProtocolService,
|
|
2190
|
+
createProtocolServiceFromContext,
|
|
2092
2191
|
createRunWorker,
|
|
2093
2192
|
encodeFrame,
|
|
2094
2193
|
encodeTerminal,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skein-js/agent-protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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.8.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.8.0"
|
|
55
55
|
},
|
|
56
56
|
"publishConfig": {
|
|
57
57
|
"access": "public"
|