@skein-js/agent-protocol 0.4.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,4 +1,4 @@
1
- import { GraphSchema, SkeinStore, RunQueue, RunEventBus, AuthEngine, Assistant, Config, StreamMode, Metadata, MultitaskStrategy, RunFrame, DefaultValues, Run, RunStatus, StorePutOptions, Item, StoreSearchQuery, SearchItem, Thread, ThreadSearchQuery, ThreadState, StoreRepo } from '@skein-js/core';
1
+ import { GraphSchema, SkeinStore, RunQueue, RunEventBus, AuthEngine, Assistant, AuthUser, Config, StreamMode, Metadata, MultitaskStrategy, RunFrame, DefaultValues, Run, RunStatus, StorePutOptions, Item, StoreSearchQuery, SearchItem, Thread, ThreadSearchQuery, ThreadState, 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. */
@@ -119,6 +119,14 @@ interface ProtocolContext {
119
119
  deps: ResolvedDeps;
120
120
  control: RunControlRegistry;
121
121
  locks: ThreadLocks;
122
+ /**
123
+ * The authenticated caller for the current request, populated by the authorizing handler wrapper
124
+ * so the run service can stamp it onto a run's kwargs. Undefined when no auth engine is
125
+ * configured (the default), matching `langgraph dev` — no principal is injected into the graph.
126
+ */
127
+ authUser?: AuthUser;
128
+ /** The current request's authenticated permission scopes (`AuthContext.scopes`), stamped with {@link authUser}. */
129
+ authScopes?: string[];
122
130
  }
123
131
  declare function createContext(deps: ProtocolDeps): ProtocolContext;
124
132
 
package/dist/index.js CHANGED
@@ -622,7 +622,10 @@ var RESERVED_CONFIGURABLE_KEYS = /* @__PURE__ */ new Set([
622
622
  "checkpoint_id",
623
623
  "checkpoint_ns",
624
624
  "checkpoint_map",
625
- "checkpoint"
625
+ "checkpoint",
626
+ "langgraph_auth_user",
627
+ "langgraph_auth_user_id",
628
+ "langgraph_auth_permissions"
626
629
  ]);
627
630
  function sanitizeConfigurable(configurable) {
628
631
  if (!configurable) return {};
@@ -633,10 +636,32 @@ function sanitizeConfigurable(configurable) {
633
636
  }
634
637
  return clean;
635
638
  }
639
+ function withAuthUser(configurable, authUser, scopes) {
640
+ if (!authUser) return configurable;
641
+ return {
642
+ ...configurable,
643
+ langgraph_auth_user: authUser,
644
+ langgraph_auth_user_id: authUser.identity,
645
+ langgraph_auth_permissions: scopes ?? authUser.permissions
646
+ };
647
+ }
648
+ function toFactoryConfigurable(kwargs) {
649
+ const configurable = withAuthUser(
650
+ sanitizeConfigurable(kwargs.config?.configurable),
651
+ kwargs.auth_user,
652
+ kwargs.auth_scopes
653
+ );
654
+ return Object.keys(configurable).length > 0 ? configurable : void 0;
655
+ }
636
656
  function toGraphCallOptions(kwargs, threadId, signal) {
637
657
  const options = {
638
- // Drop server-owned keys from the client's configurable, then force this thread's id.
639
- configurable: { ...sanitizeConfigurable(kwargs.config?.configurable), thread_id: threadId },
658
+ // Drop server-owned keys from the client's configurable, force this thread's id, then stamp the
659
+ // authenticated caller so the graph can authorize off `configurable.langgraph_auth_user`.
660
+ configurable: withAuthUser(
661
+ { ...sanitizeConfigurable(kwargs.config?.configurable), thread_id: threadId },
662
+ kwargs.auth_user,
663
+ kwargs.auth_scopes
664
+ ),
640
665
  streamMode: normalizeModes(kwargs.stream_mode),
641
666
  signal
642
667
  };
@@ -717,7 +742,12 @@ function describeInterrupts(snapshot) {
717
742
  // src/runs/run-engine.ts
718
743
  async function resolveGraph(deps, graphId, kwargs) {
719
744
  const resolved = await deps.graphs.load(graphId);
720
- const graph = typeof resolved === "function" ? await resolved({ configurable: kwargs.config?.configurable }) : resolved;
745
+ const graph = typeof resolved === "function" ? (
746
+ // Expose the authenticated caller to a graph *factory* too, so a factory that branches on the
747
+ // principal sees the same `langgraph_auth_user` a node reads — sanitized identically, so a
748
+ // client can't spoof it via its own configurable.
749
+ await resolved({ configurable: toFactoryConfigurable(kwargs) })
750
+ ) : resolved;
721
751
  graph.checkpointer = deps.checkpointer;
722
752
  graph.store = new SkeinBaseStore(deps.store.store);
723
753
  return graph;
@@ -855,7 +885,7 @@ async function executeRun(deps, exec) {
855
885
  }
856
886
 
857
887
  // src/runs/run-service.ts
858
- function toKwargs(input) {
888
+ function toKwargs(input, authUser, authScopes) {
859
889
  const kwargs = {};
860
890
  if (input.input !== void 0) kwargs.input = input.input;
861
891
  if (input.command !== void 0) kwargs.command = input.command;
@@ -864,10 +894,14 @@ function toKwargs(input) {
864
894
  if (input.stream_mode !== void 0) kwargs.stream_mode = input.stream_mode;
865
895
  if (input.interrupt_before !== void 0) kwargs.interrupt_before = input.interrupt_before;
866
896
  if (input.interrupt_after !== void 0) kwargs.interrupt_after = input.interrupt_after;
897
+ if (authUser !== void 0) {
898
+ kwargs.auth_user = authUser;
899
+ if (authScopes !== void 0) kwargs.auth_scopes = authScopes;
900
+ }
867
901
  return kwargs;
868
902
  }
869
903
  function createRunService(ctx) {
870
- const { deps, control, locks } = ctx;
904
+ const { deps, control, locks, authUser, authScopes } = ctx;
871
905
  const requireThread = async (threadId) => {
872
906
  const thread = await deps.store.threads.get(threadId);
873
907
  if (!thread) throw SkeinHttpError5.notFound(`Thread "${threadId}" not found.`);
@@ -931,7 +965,7 @@ function createRunService(ctx) {
931
965
  async createWait(input) {
932
966
  const assistant = await requireAssistant(input.assistant_id);
933
967
  const thread = await ensureThread(input.thread_id);
934
- const kwargs = toKwargs(input);
968
+ const kwargs = toKwargs(input, authUser, authScopes);
935
969
  const run = await createPendingRun(input, thread.thread_id, assistant.assistant_id, kwargs);
936
970
  await stampGraphOnThread(thread, assistant);
937
971
  const outcome = await runInline(run, kwargs);
@@ -940,7 +974,7 @@ function createRunService(ctx) {
940
974
  async createStream(input) {
941
975
  const assistant = await requireAssistant(input.assistant_id);
942
976
  const thread = await ensureThread(input.thread_id);
943
- const kwargs = toKwargs(input);
977
+ const kwargs = toKwargs(input, authUser, authScopes);
944
978
  const run = await createPendingRun(input, thread.thread_id, assistant.assistant_id, kwargs);
945
979
  await stampGraphOnThread(thread, assistant);
946
980
  void runInline(run, kwargs).catch(
@@ -951,7 +985,7 @@ function createRunService(ctx) {
951
985
  async createBackground(threadId, input) {
952
986
  const assistant = await requireAssistant(input.assistant_id);
953
987
  const thread = await requireThread(threadId);
954
- const kwargs = toKwargs(input);
988
+ const kwargs = toKwargs(input, authUser, authScopes);
955
989
  const run = await createPendingRun(
956
990
  { ...input, thread_id: threadId },
957
991
  threadId,
@@ -1410,7 +1444,7 @@ var STUDIO_USER = {
1410
1444
  };
1411
1445
  function createAuthorizingHandlers(context, engine) {
1412
1446
  const baseHandlers = createProtocolHandlers(buildProtocolService(context));
1413
- const names = Object.keys(baseHandlers);
1447
+ const names = Object.keys(ROUTE_AUTHZ);
1414
1448
  const resolveAuthContext = async (req) => {
1415
1449
  if (!engine.studioAuthDisabled && req.headers["x-auth-scheme"] === "langsmith") {
1416
1450
  return { user: STUDIO_USER, scopes: [] };
@@ -1428,13 +1462,17 @@ function createAuthorizingHandlers(context, engine) {
1428
1462
  value: authValue(req),
1429
1463
  context: authContext
1430
1464
  });
1431
- if (!filters) return baseHandlers[name](req);
1432
- const scopedStore = createAuthScopedStore(context.deps.store, engine, filters, route.resource);
1433
- const scopedContext = {
1465
+ if (!filters && !authContext) return baseHandlers[name](req);
1466
+ const requestContext = {
1434
1467
  ...context,
1435
- deps: { ...context.deps, store: scopedStore }
1468
+ authUser: authContext?.user,
1469
+ authScopes: authContext?.scopes,
1470
+ deps: filters ? {
1471
+ ...context.deps,
1472
+ store: createAuthScopedStore(context.deps.store, engine, filters, route.resource)
1473
+ } : context.deps
1436
1474
  };
1437
- return createProtocolHandlers(buildProtocolService(scopedContext))[name](req);
1475
+ return createProtocolHandlers(buildProtocolService(requestContext))[name](req);
1438
1476
  };
1439
1477
  }
1440
1478
  return wrapped;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skein-js/agent-protocol",
3
- "version": "0.4.0",
3
+ "version": "0.5.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.4.0"
47
+ "@skein-js/core": "0.5.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.4.0"
54
+ "@skein-js/storage-memory": "0.5.0"
55
55
  },
56
56
  "publishConfig": {
57
57
  "access": "public"