@stigmer/react 3.5.0 → 3.5.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stigmer/react",
3
- "version": "3.5.0",
3
+ "version": "3.5.1",
4
4
  "description": "React provider and client hook for the Stigmer platform SDK",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -37,7 +37,7 @@
37
37
  "dependencies": {
38
38
  "@bufbuild/protovalidate": "^1.1.1",
39
39
  "@dagrejs/dagre": "^1.1.4",
40
- "@stigmer/theme": "3.5.0",
40
+ "@stigmer/theme": "3.5.1",
41
41
  "diff": "^8.0.3",
42
42
  "fflate": "^0.8.2",
43
43
  "hast-util-to-jsx-runtime": "^2.3.6",
@@ -60,8 +60,8 @@
60
60
  "@codemirror/state": "^6.0.0",
61
61
  "@codemirror/view": "^6.0.0",
62
62
  "@lezer/highlight": "^1.0.0",
63
- "@stigmer/protos": "3.5.0",
64
- "@stigmer/sdk": "3.5.0",
63
+ "@stigmer/protos": "3.5.1",
64
+ "@stigmer/sdk": "3.5.1",
65
65
  "@tanstack/react-table": "^8.20.0",
66
66
  "@xyflow/react": "^12.0.0",
67
67
  "elkjs": "^0.9.0",
@@ -62,5 +62,19 @@ export interface UseSessionExecutionsReturn {
62
62
  * const { executions } = useSessionExecutions(sessionId ?? null);
63
63
  * ```
64
64
  */
65
+ /**
66
+ * Returns the executions in chronological (oldest-first) order — the order
67
+ * the conversation thread renders top-to-bottom.
68
+ *
69
+ * Defense-in-depth against an unordered list response: the executions ARE the
70
+ * transcript, so a scrambled order drops the newest turns out of view (they no
71
+ * longer sort to the bottom). The server orders this list, but the thread must
72
+ * never depend on that alone. Resource ids are time-sortable ULIDs
73
+ * (`aex_01k…`), so an ascending id sort is creation order without parsing
74
+ * timestamps; entries missing an id sort last but keep a stable relative order.
75
+ *
76
+ * @internal Exported for testing — not part of the public API.
77
+ */
78
+ export declare function sortChronologically(executions: readonly AgentExecution[]): AgentExecution[];
65
79
  export declare function useSessionExecutions(sessionId: string | null, options?: UseSessionExecutionsOptions): UseSessionExecutionsReturn;
66
80
  //# sourceMappingURL=useSessionExecutions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSessionExecutions.d.ts","sourceRoot":"","sources":["../../src/session/useSessionExecutions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6DAA6D,CAAC;AAKlG,gDAAgD;AAChD,MAAM,WAAW,2BAA2B;IAC1C;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CACzC;AAED,oDAAoD;AACpD,MAAM,WAAW,0BAA0B;IACzC,uEAAuE;IACvE,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C,mDAAmD;IACnD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,sDAAsD;IACtD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,OAAO,CAAC,EAAE,2BAA2B,GACpC,0BAA0B,CAyB5B"}
1
+ {"version":3,"file":"useSessionExecutions.d.ts","sourceRoot":"","sources":["../../src/session/useSessionExecutions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6DAA6D,CAAC;AAKlG,gDAAgD;AAChD,MAAM,WAAW,2BAA2B;IAC1C;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CACzC;AAED,oDAAoD;AACpD,MAAM,WAAW,0BAA0B;IACzC,uEAAuE;IACvE,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C,mDAAmD;IACnD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,sDAAsD;IACtD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,SAAS,cAAc,EAAE,GACpC,cAAc,EAAE,CASlB;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,OAAO,CAAC,EAAE,2BAA2B,GACpC,0BAA0B,CAyB5B"}
@@ -37,6 +37,32 @@ import { useFetch } from "../internal/useFetch.js";
37
37
  * const { executions } = useSessionExecutions(sessionId ?? null);
38
38
  * ```
39
39
  */
40
+ /**
41
+ * Returns the executions in chronological (oldest-first) order — the order
42
+ * the conversation thread renders top-to-bottom.
43
+ *
44
+ * Defense-in-depth against an unordered list response: the executions ARE the
45
+ * transcript, so a scrambled order drops the newest turns out of view (they no
46
+ * longer sort to the bottom). The server orders this list, but the thread must
47
+ * never depend on that alone. Resource ids are time-sortable ULIDs
48
+ * (`aex_01k…`), so an ascending id sort is creation order without parsing
49
+ * timestamps; entries missing an id sort last but keep a stable relative order.
50
+ *
51
+ * @internal Exported for testing — not part of the public API.
52
+ */
53
+ export function sortChronologically(executions) {
54
+ return [...executions].sort((a, b) => {
55
+ const aId = a.metadata?.id ?? "";
56
+ const bId = b.metadata?.id ?? "";
57
+ if (aId === bId)
58
+ return 0;
59
+ if (!aId)
60
+ return 1;
61
+ if (!bId)
62
+ return -1;
63
+ return aId < bId ? -1 : 1;
64
+ });
65
+ }
40
66
  export function useSessionExecutions(sessionId, options) {
41
67
  const stigmer = useStigmer();
42
68
  const { data: executions, isLoading, isRefetching, error, refetch } = useFetch(sessionId
@@ -45,7 +71,7 @@ export function useSessionExecutions(sessionId, options) {
45
71
  sessionId,
46
72
  pageSize: 100,
47
73
  }))
48
- .then((result) => result.entries)
74
+ .then((result) => sortChronologically(result.entries))
49
75
  : null, [sessionId, stigmer], [], {
50
76
  cacheKey: sessionId ? `session-executions:${sessionId}` : undefined,
51
77
  refetchInterval: options?.refetchInterval,
@@ -1 +1 @@
1
- {"version":3,"file":"useSessionExecutions.js","sourceRoot":"","sources":["../../src/session/useSessionExecutions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,yCAAyC,EAAE,MAAM,4DAA4D,CAAC;AACvH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAiCnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,UAAU,oBAAoB,CAClC,SAAwB,EACxB,OAAqC;IAErC,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,QAAQ,CAC5E,SAAS;QACP,CAAC,CAAC,GAAG,EAAE,CACH,OAAO,CAAC,cAAc;aACnB,aAAa,CACZ,MAAM,CAAC,yCAAyC,EAAE;YAChD,SAAS;YACT,QAAQ,EAAE,GAAG;SACd,CAAC,CACH;aACA,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;QACvC,CAAC,CAAC,IAAI,EACR,CAAC,SAAS,EAAE,OAAO,CAAC,EACpB,EAAsB,EACtB;QACE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS;QACnE,eAAe,EAAE,OAAO,EAAE,eAAe;QACzC,oBAAoB,EAAE,OAAO,EAAE,oBAAoB;KACpD,CACF,CAAC;IAEF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACjE,CAAC"}
1
+ {"version":3,"file":"useSessionExecutions.js","sourceRoot":"","sources":["../../src/session/useSessionExecutions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,yCAAyC,EAAE,MAAM,4DAA4D,CAAC;AACvH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAiCnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CACjC,UAAqC;IAErC,OAAO,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACnC,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC;QACjC,IAAI,GAAG,KAAK,GAAG;YAAE,OAAO,CAAC,CAAC;QAC1B,IAAI,CAAC,GAAG;YAAE,OAAO,CAAC,CAAC;QACnB,IAAI,CAAC,GAAG;YAAE,OAAO,CAAC,CAAC,CAAC;QACpB,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,SAAwB,EACxB,OAAqC;IAErC,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,QAAQ,CAC5E,SAAS;QACP,CAAC,CAAC,GAAG,EAAE,CACH,OAAO,CAAC,cAAc;aACnB,aAAa,CACZ,MAAM,CAAC,yCAAyC,EAAE;YAChD,SAAS;YACT,QAAQ,EAAE,GAAG;SACd,CAAC,CACH;aACA,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5D,CAAC,CAAC,IAAI,EACR,CAAC,SAAS,EAAE,OAAO,CAAC,EACpB,EAAsB,EACtB;QACE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS;QACnE,eAAe,EAAE,OAAO,EAAE,eAAe;QACzC,oBAAoB,EAAE,OAAO,EAAE,oBAAoB;KACpD,CACF,CAAC;IAEF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACjE,CAAC"}
@@ -0,0 +1,63 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { create } from "@bufbuild/protobuf";
3
+ import {
4
+ AgentExecutionSchema,
5
+ type AgentExecution,
6
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
7
+ import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
8
+ import { sortChronologically } from "../useSessionExecutions";
9
+
10
+ function exec(id: string): AgentExecution {
11
+ const e = create(AgentExecutionSchema);
12
+ const metadata = create(ApiResourceMetadataSchema);
13
+ metadata.id = id;
14
+ e.metadata = metadata;
15
+ return e;
16
+ }
17
+
18
+ function ids(list: readonly AgentExecution[]): string[] {
19
+ return list.map((e) => e.metadata?.id ?? "");
20
+ }
21
+
22
+ describe("sortChronologically", () => {
23
+ it("orders executions oldest-first by their ULID id", () => {
24
+ // Real ids from the pilot session, returned by the server in scrambled
25
+ // heap order — the afternoon turns (…vk…) interleaved with the evening
26
+ // turns (…w3…/…w4…). Chronological order is ascending ULID.
27
+ const scrambled = [
28
+ exec("aex_01kyw3zeq8cre6cc8gznf31y13"),
29
+ exec("aex_01kyvk1hxyrhch1q23p5j177pb"),
30
+ exec("aex_01kyw416w9mg6ezzpkc6q9y71x"),
31
+ exec("aex_01kyvk2sh0vjc69c7z3q4c9r1m"),
32
+ exec("aex_01kyw45qkf88x28pf9bxmrr3bf"),
33
+ exec("aex_01kyw3y0rfx9vd7dhnawgqgnb0"),
34
+ exec("aex_01kyvk3v34vh9phedx2ezajxtr"),
35
+ ];
36
+
37
+ expect(ids(sortChronologically(scrambled))).toEqual([
38
+ "aex_01kyvk1hxyrhch1q23p5j177pb",
39
+ "aex_01kyvk2sh0vjc69c7z3q4c9r1m",
40
+ "aex_01kyvk3v34vh9phedx2ezajxtr",
41
+ "aex_01kyw3y0rfx9vd7dhnawgqgnb0",
42
+ "aex_01kyw3zeq8cre6cc8gznf31y13",
43
+ "aex_01kyw416w9mg6ezzpkc6q9y71x",
44
+ "aex_01kyw45qkf88x28pf9bxmrr3bf",
45
+ ]);
46
+ });
47
+
48
+ it("does not mutate the input array", () => {
49
+ const input = [exec("aex_02"), exec("aex_01")];
50
+ const before = ids(input);
51
+ sortChronologically(input);
52
+ expect(ids(input)).toEqual(before);
53
+ });
54
+
55
+ it("sorts entries missing an id last", () => {
56
+ const list = [exec("aex_02"), exec(""), exec("aex_01")];
57
+ expect(ids(sortChronologically(list))).toEqual(["aex_01", "aex_02", ""]);
58
+ });
59
+
60
+ it("returns an empty array unchanged", () => {
61
+ expect(sortChronologically([])).toEqual([]);
62
+ });
63
+ });
@@ -71,6 +71,32 @@ export interface UseSessionExecutionsReturn {
71
71
  * const { executions } = useSessionExecutions(sessionId ?? null);
72
72
  * ```
73
73
  */
74
+ /**
75
+ * Returns the executions in chronological (oldest-first) order — the order
76
+ * the conversation thread renders top-to-bottom.
77
+ *
78
+ * Defense-in-depth against an unordered list response: the executions ARE the
79
+ * transcript, so a scrambled order drops the newest turns out of view (they no
80
+ * longer sort to the bottom). The server orders this list, but the thread must
81
+ * never depend on that alone. Resource ids are time-sortable ULIDs
82
+ * (`aex_01k…`), so an ascending id sort is creation order without parsing
83
+ * timestamps; entries missing an id sort last but keep a stable relative order.
84
+ *
85
+ * @internal Exported for testing — not part of the public API.
86
+ */
87
+ export function sortChronologically(
88
+ executions: readonly AgentExecution[],
89
+ ): AgentExecution[] {
90
+ return [...executions].sort((a, b) => {
91
+ const aId = a.metadata?.id ?? "";
92
+ const bId = b.metadata?.id ?? "";
93
+ if (aId === bId) return 0;
94
+ if (!aId) return 1;
95
+ if (!bId) return -1;
96
+ return aId < bId ? -1 : 1;
97
+ });
98
+ }
99
+
74
100
  export function useSessionExecutions(
75
101
  sessionId: string | null,
76
102
  options?: UseSessionExecutionsOptions,
@@ -87,7 +113,7 @@ export function useSessionExecutions(
87
113
  pageSize: 100,
88
114
  }),
89
115
  )
90
- .then((result) => result.entries)
116
+ .then((result) => sortChronologically(result.entries))
91
117
  : null,
92
118
  [sessionId, stigmer],
93
119
  [] as AgentExecution[],