@tai42/studio-sdk 0.5.0 → 0.5.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"useSse.d.ts","sourceRoot":"","sources":["../../src/hooks/useSse.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKrD,qEAAqE;AACrE,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAE7E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAC3C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CAC9B;AAqHD,wBAAgB,qBAAqB,IAAI,uBAAuB,CAmK/D"}
1
+ {"version":3,"file":"useSse.d.ts","sourceRoot":"","sources":["../../src/hooks/useSse.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKrD,qEAAqE;AACrE,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAU7E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAC3C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CAC9B;AA+HD,wBAAgB,qBAAqB,IAAI,uBAAuB,CAgN/D"}
@@ -6,10 +6,23 @@
6
6
  * `interaction.answered` / `interaction.removed` / `interaction.backlog_done`.
7
7
  * The `add` frame (backlog on connect + live tail) carries the full question;
8
8
  * `answered` / `removed` frames carry only ids. On (re)connect the server
9
- * replays the current pending set as the backlog; this hook treats that backlog
10
- * as authoritative — an entry not re-seen by `interaction.backlog_done` is
11
- * dropped, so an interaction removed while the client was disconnected does not
12
- * linger. `add` frames are at-least-once, so entries are de-duplicated by
9
+ * replays the current PENDING set as the backlog (answered items are NOT in it);
10
+ * this hook treats that backlog as authoritative for the PENDING set only — a
11
+ * still-pending entry not re-seen by `interaction.backlog_done` is dropped
12
+ * (removed while the client was disconnected), while a locally-ANSWERED entry is
13
+ * exempt from that reconcile so it survives reconnect (reconcile-deleting it
14
+ * would vanish an answered card on the next reconnect, since the pending-only
15
+ * backlog never replays it).
16
+ *
17
+ * ANSWERED-CARD LIFECYCLE: the server emits no removal for an answered card —
18
+ * only `interaction.answered`, never `interaction.removed` for it — so answered
19
+ * cards would otherwise pile up unbounded in the always-mounted badge/inbox. This
20
+ * hook AGES them out itself: an answered card is dropped once it is older than
21
+ * `ANSWERED_RETENTION_MS`, with `ANSWERED_CAP` as a hard newest-N flood backstop.
22
+ * Both are swept lazily on frame/reconnect ticks (the stream carries no idle
23
+ * heartbeat frame), never a per-item timer.
24
+ *
25
+ * `add` frames are at-least-once, so entries are de-duplicated by
13
26
  * `interaction_id`, and a redelivered `add` preserves the client `answered` flag.
14
27
  *
15
28
  * The `Interaction` type is imported type-only (no runtime dep on api-client);
@@ -29,6 +42,15 @@ import { useOnUnauthorized } from './useUnauthorized';
29
42
  // clients apart rather than retrying in lockstep.
30
43
  const RECONNECT_BASE_MS = 1500;
31
44
  const RECONNECT_CAP_MS = 30000;
45
+ // The server emits no removal for an answered card — only `interaction.answered`,
46
+ // never `interaction.removed` for it — so answered cards would otherwise pile up
47
+ // unbounded in the always-mounted badge/inbox. The client ages them out: drop an
48
+ // answered card ANSWERED_RETENTION_MS after its answered frame (a "recently
49
+ // answered" window), keeping at most ANSWERED_CAP as a hard flood backstop. Swept
50
+ // lazily on frame/reconnect ticks (the stream carries no idle heartbeat frame),
51
+ // never a per-item timer.
52
+ const ANSWERED_RETENTION_MS = 10 * 60 * 1000;
53
+ const ANSWERED_CAP = 200;
32
54
  // The wire `answer_format` values. Duplicated from the api-client enum by design:
33
55
  // the SDK is the leaf and must not import api-client at runtime. The `satisfies`
34
56
  // pin against `Interaction['answer_format']` fails to compile if a listed value
@@ -146,21 +168,50 @@ export function useInteractionsStream() {
146
168
  useEffect(() => {
147
169
  const controller = new AbortController();
148
170
  const aborted = () => controller.signal.aborted;
171
+ // The published list carries the public shape only — the internal
172
+ // `answeredAt` aging stamp is stripped here.
173
+ const toPublicList = () => Array.from(mapRef.current.values(), ({ answeredAt: _answeredAt, ...rest }) => rest);
174
+ // Age answered cards out (the server sends no removal for them): drop any past
175
+ // the retention window, then — as a flood backstop — the oldest beyond the
176
+ // count cap. Pending items (`answeredAt === null`) are never touched. Called on
177
+ // every frame/reconnect tick so the always-mounted badge cannot grow unbounded.
178
+ const sweepAnswered = () => {
179
+ const now = Date.now();
180
+ const answered = [];
181
+ for (const entry of mapRef.current.values()) {
182
+ if (entry.answeredAt !== null) {
183
+ answered.push({ id: entry.interaction_id, answeredAt: entry.answeredAt });
184
+ }
185
+ }
186
+ for (const { id, answeredAt } of answered) {
187
+ if (now - answeredAt >= ANSWERED_RETENTION_MS)
188
+ mapRef.current.delete(id);
189
+ }
190
+ const live = answered.filter(({ id }) => mapRef.current.has(id));
191
+ if (live.length > ANSWERED_CAP) {
192
+ live.sort((a, b) => a.answeredAt - b.answeredAt); // oldest first
193
+ for (const { id } of live.slice(0, live.length - ANSWERED_CAP)) {
194
+ mapRef.current.delete(id);
195
+ }
196
+ }
197
+ };
149
198
  // A successful data frame rebuilds the list and clears any transient
150
199
  // frame-parse error — one bad frame on a healthy stream must not stick.
151
200
  const publish = () => {
201
+ sweepAnswered();
152
202
  setState((prev) => ({
153
203
  ...prev,
154
- interactions: Array.from(mapRef.current.values()),
204
+ interactions: toPublicList(),
155
205
  error: null,
156
206
  }));
157
207
  };
158
208
  const surfaceMalformed = (event) => {
159
209
  setState((prev) => ({ ...prev, error: new Error(`malformed interaction frame: ${event}`) }));
160
210
  };
161
- // Per-connection reconcile state: the replayed backlog is authoritative, so
162
- // ids not re-seen by `interaction.backlog_done` are dropped as
163
- // removed-while-disconnected.
211
+ // Per-connection reconcile state: the replayed backlog is the PENDING set
212
+ // only, so a still-pending id not re-seen by `interaction.backlog_done` is
213
+ // dropped (removed while disconnected); a locally-answered id is exempt — it
214
+ // survives reconnect and is aged out client-side (see `sweepAnswered`).
164
215
  let reconciling = false;
165
216
  let seenInBacklog = new Set();
166
217
  // Consecutive failed reconnect attempts. Reset only when a connection proves
@@ -175,8 +226,13 @@ export function useInteractionsStream() {
175
226
  const applyFrame = (event, data) => {
176
227
  if (event === 'interaction.backlog_done') {
177
228
  if (reconciling) {
178
- for (const id of mapRef.current.keys()) {
179
- if (!seenInBacklog.has(id))
229
+ // The pending-only backlog is authoritative for pending items alone:
230
+ // drop a still-pending id it did not replay (removed while
231
+ // disconnected), but NEVER an answered id — that is terminal and the
232
+ // backlog never carries it, so reconcile-deleting it would vanish an
233
+ // answered card on every reconnect.
234
+ for (const [id, item] of mapRef.current) {
235
+ if (!seenInBacklog.has(id) && !item.answered)
180
236
  mapRef.current.delete(id);
181
237
  }
182
238
  reconciling = false;
@@ -184,9 +240,10 @@ export function useInteractionsStream() {
184
240
  // A completed backlog is proof the connection is healthy — clear the
185
241
  // reconnect backoff so the next drop reconnects promptly.
186
242
  reconnectAttempt = 0;
243
+ sweepAnswered();
187
244
  setState((prev) => ({
188
245
  ...prev,
189
- interactions: Array.from(mapRef.current.values()),
246
+ interactions: toPublicList(),
190
247
  backlogLoaded: true,
191
248
  }));
192
249
  return;
@@ -209,10 +266,14 @@ export function useInteractionsStream() {
209
266
  }
210
267
  // The answered frame carries only ids — flip the existing item's flag,
211
268
  // keeping its question/format. An answered event for an item we never saw
212
- // has nothing to show.
269
+ // has nothing to show. Stamp the answered time on the FIRST answered frame
270
+ // only; a redelivered answered keeps the original stamp so the retention
271
+ // window is not extended.
213
272
  const existing = mapRef.current.get(id);
214
- if (existing)
215
- mapRef.current.set(id, { ...existing, answered: true });
273
+ if (existing) {
274
+ const answeredAt = existing.answered ? existing.answeredAt : Date.now();
275
+ mapRef.current.set(id, { ...existing, answered: true, answeredAt });
276
+ }
216
277
  publish();
217
278
  return;
218
279
  }
@@ -224,12 +285,15 @@ export function useInteractionsStream() {
224
285
  }
225
286
  if (reconciling)
226
287
  seenInBacklog.add(interaction.interaction_id);
227
- // Dedupe by id; a redelivered add preserves the client answered flag so a
228
- // prior `answered` is not undone by an at-least-once replay.
288
+ // Dedupe by id; a redelivered add preserves the client answered flag (and
289
+ // its aging stamp) so a prior `answered` is not undone by an at-least-once
290
+ // replay. A fresh (pending) add carries no stamp until its answered frame.
229
291
  const existing = mapRef.current.get(interaction.interaction_id);
292
+ const answered = existing?.answered ?? false;
230
293
  mapRef.current.set(interaction.interaction_id, {
231
294
  ...interaction,
232
- answered: existing?.answered ?? false,
295
+ answered,
296
+ answeredAt: answered ? (existing?.answeredAt ?? null) : null,
233
297
  });
234
298
  publish();
235
299
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useSse.js","sourceRoot":"","sources":["../../src/hooks/useSse.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useSse.js","sourceRoot":"","sources":["../../src/hooks/useSse.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tai42/studio-sdk",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "The Studio plugin contract, shared UI components, and hooks that every feature builds on.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "tai42 <oss@tai42.ai>",
@@ -89,7 +89,7 @@
89
89
  "@radix-ui/react-select": "^2.3.2",
90
90
  "@radix-ui/react-tabs": "^1.1.16",
91
91
  "@radix-ui/react-tooltip": "^1.2.11",
92
- "@tai42/api-client": "0.5.0"
92
+ "@tai42/api-client": "0.5.2"
93
93
  },
94
94
  "scripts": {
95
95
  "build": "tsc -b tsconfig.build.json && node scripts/copy-assets.mjs",
@@ -6,10 +6,23 @@
6
6
  * `interaction.answered` / `interaction.removed` / `interaction.backlog_done`.
7
7
  * The `add` frame (backlog on connect + live tail) carries the full question;
8
8
  * `answered` / `removed` frames carry only ids. On (re)connect the server
9
- * replays the current pending set as the backlog; this hook treats that backlog
10
- * as authoritative — an entry not re-seen by `interaction.backlog_done` is
11
- * dropped, so an interaction removed while the client was disconnected does not
12
- * linger. `add` frames are at-least-once, so entries are de-duplicated by
9
+ * replays the current PENDING set as the backlog (answered items are NOT in it);
10
+ * this hook treats that backlog as authoritative for the PENDING set only — a
11
+ * still-pending entry not re-seen by `interaction.backlog_done` is dropped
12
+ * (removed while the client was disconnected), while a locally-ANSWERED entry is
13
+ * exempt from that reconcile so it survives reconnect (reconcile-deleting it
14
+ * would vanish an answered card on the next reconnect, since the pending-only
15
+ * backlog never replays it).
16
+ *
17
+ * ANSWERED-CARD LIFECYCLE: the server emits no removal for an answered card —
18
+ * only `interaction.answered`, never `interaction.removed` for it — so answered
19
+ * cards would otherwise pile up unbounded in the always-mounted badge/inbox. This
20
+ * hook AGES them out itself: an answered card is dropped once it is older than
21
+ * `ANSWERED_RETENTION_MS`, with `ANSWERED_CAP` as a hard newest-N flood backstop.
22
+ * Both are swept lazily on frame/reconnect ticks (the stream carries no idle
23
+ * heartbeat frame), never a per-item timer.
24
+ *
25
+ * `add` frames are at-least-once, so entries are de-duplicated by
13
26
  * `interaction_id`, and a redelivered `add` preserves the client `answered` flag.
14
27
  *
15
28
  * The `Interaction` type is imported type-only (no runtime dep on api-client);
@@ -26,6 +39,14 @@ import { useOnUnauthorized } from './useUnauthorized';
26
39
  /** A live interaction plus the client-maintained `answered` flag. */
27
40
  export type StreamInteraction = Interaction & { readonly answered: boolean };
28
41
 
42
+ /**
43
+ * The internal map value: a `StreamInteraction` plus the wall-clock ms of its
44
+ * answered frame (`null` while pending), read only by the client-side aging
45
+ * sweep. `answeredAt` is stripped before the interaction is published — it is not
46
+ * part of the public `StreamInteraction` contract.
47
+ */
48
+ type TrackedInteraction = StreamInteraction & { readonly answeredAt: number | null };
49
+
29
50
  export interface InteractionsStreamState {
30
51
  readonly interactions: StreamInteraction[];
31
52
  readonly connected: boolean;
@@ -43,6 +64,16 @@ export interface InteractionsStreamState {
43
64
  const RECONNECT_BASE_MS = 1500;
44
65
  const RECONNECT_CAP_MS = 30000;
45
66
 
67
+ // The server emits no removal for an answered card — only `interaction.answered`,
68
+ // never `interaction.removed` for it — so answered cards would otherwise pile up
69
+ // unbounded in the always-mounted badge/inbox. The client ages them out: drop an
70
+ // answered card ANSWERED_RETENTION_MS after its answered frame (a "recently
71
+ // answered" window), keeping at most ANSWERED_CAP as a hard flood backstop. Swept
72
+ // lazily on frame/reconnect ticks (the stream carries no idle heartbeat frame),
73
+ // never a per-item timer.
74
+ const ANSWERED_RETENTION_MS = 10 * 60 * 1000;
75
+ const ANSWERED_CAP = 200;
76
+
46
77
  // The wire `answer_format` values. Duplicated from the api-client enum by design:
47
78
  // the SDK is the leaf and must not import api-client at runtime. The `satisfies`
48
79
  // pin against `Interaction['answer_format']` fails to compile if a listed value
@@ -159,18 +190,48 @@ export function useInteractionsStream(): InteractionsStreamState {
159
190
  });
160
191
  // Source of truth: a dedupe map keyed by interaction_id, rebuilt into the
161
192
  // ordered array on every change.
162
- const mapRef = useRef<Map<string, StreamInteraction>>(new Map());
193
+ const mapRef = useRef<Map<string, TrackedInteraction>>(new Map());
163
194
 
164
195
  useEffect(() => {
165
196
  const controller = new AbortController();
166
197
  const aborted = () => controller.signal.aborted;
167
198
 
199
+ // The published list carries the public shape only — the internal
200
+ // `answeredAt` aging stamp is stripped here.
201
+ const toPublicList = (): StreamInteraction[] =>
202
+ Array.from(mapRef.current.values(), ({ answeredAt: _answeredAt, ...rest }) => rest);
203
+
204
+ // Age answered cards out (the server sends no removal for them): drop any past
205
+ // the retention window, then — as a flood backstop — the oldest beyond the
206
+ // count cap. Pending items (`answeredAt === null`) are never touched. Called on
207
+ // every frame/reconnect tick so the always-mounted badge cannot grow unbounded.
208
+ const sweepAnswered = () => {
209
+ const now = Date.now();
210
+ const answered: { id: string; answeredAt: number }[] = [];
211
+ for (const entry of mapRef.current.values()) {
212
+ if (entry.answeredAt !== null) {
213
+ answered.push({ id: entry.interaction_id, answeredAt: entry.answeredAt });
214
+ }
215
+ }
216
+ for (const { id, answeredAt } of answered) {
217
+ if (now - answeredAt >= ANSWERED_RETENTION_MS) mapRef.current.delete(id);
218
+ }
219
+ const live = answered.filter(({ id }) => mapRef.current.has(id));
220
+ if (live.length > ANSWERED_CAP) {
221
+ live.sort((a, b) => a.answeredAt - b.answeredAt); // oldest first
222
+ for (const { id } of live.slice(0, live.length - ANSWERED_CAP)) {
223
+ mapRef.current.delete(id);
224
+ }
225
+ }
226
+ };
227
+
168
228
  // A successful data frame rebuilds the list and clears any transient
169
229
  // frame-parse error — one bad frame on a healthy stream must not stick.
170
230
  const publish = () => {
231
+ sweepAnswered();
171
232
  setState((prev) => ({
172
233
  ...prev,
173
- interactions: Array.from(mapRef.current.values()),
234
+ interactions: toPublicList(),
174
235
  error: null,
175
236
  }));
176
237
  };
@@ -179,9 +240,10 @@ export function useInteractionsStream(): InteractionsStreamState {
179
240
  setState((prev) => ({ ...prev, error: new Error(`malformed interaction frame: ${event}`) }));
180
241
  };
181
242
 
182
- // Per-connection reconcile state: the replayed backlog is authoritative, so
183
- // ids not re-seen by `interaction.backlog_done` are dropped as
184
- // removed-while-disconnected.
243
+ // Per-connection reconcile state: the replayed backlog is the PENDING set
244
+ // only, so a still-pending id not re-seen by `interaction.backlog_done` is
245
+ // dropped (removed while disconnected); a locally-answered id is exempt — it
246
+ // survives reconnect and is aged out client-side (see `sweepAnswered`).
185
247
  let reconciling = false;
186
248
  let seenInBacklog = new Set<string>();
187
249
  // Consecutive failed reconnect attempts. Reset only when a connection proves
@@ -197,17 +259,23 @@ export function useInteractionsStream(): InteractionsStreamState {
197
259
  const applyFrame = (event: string, data: string) => {
198
260
  if (event === 'interaction.backlog_done') {
199
261
  if (reconciling) {
200
- for (const id of mapRef.current.keys()) {
201
- if (!seenInBacklog.has(id)) mapRef.current.delete(id);
262
+ // The pending-only backlog is authoritative for pending items alone:
263
+ // drop a still-pending id it did not replay (removed while
264
+ // disconnected), but NEVER an answered id — that is terminal and the
265
+ // backlog never carries it, so reconcile-deleting it would vanish an
266
+ // answered card on every reconnect.
267
+ for (const [id, item] of mapRef.current) {
268
+ if (!seenInBacklog.has(id) && !item.answered) mapRef.current.delete(id);
202
269
  }
203
270
  reconciling = false;
204
271
  }
205
272
  // A completed backlog is proof the connection is healthy — clear the
206
273
  // reconnect backoff so the next drop reconnects promptly.
207
274
  reconnectAttempt = 0;
275
+ sweepAnswered();
208
276
  setState((prev) => ({
209
277
  ...prev,
210
- interactions: Array.from(mapRef.current.values()),
278
+ interactions: toPublicList(),
211
279
  backlogLoaded: true,
212
280
  }));
213
281
  return;
@@ -230,9 +298,14 @@ export function useInteractionsStream(): InteractionsStreamState {
230
298
  }
231
299
  // The answered frame carries only ids — flip the existing item's flag,
232
300
  // keeping its question/format. An answered event for an item we never saw
233
- // has nothing to show.
301
+ // has nothing to show. Stamp the answered time on the FIRST answered frame
302
+ // only; a redelivered answered keeps the original stamp so the retention
303
+ // window is not extended.
234
304
  const existing = mapRef.current.get(id);
235
- if (existing) mapRef.current.set(id, { ...existing, answered: true });
305
+ if (existing) {
306
+ const answeredAt = existing.answered ? existing.answeredAt : Date.now();
307
+ mapRef.current.set(id, { ...existing, answered: true, answeredAt });
308
+ }
236
309
  publish();
237
310
  return;
238
311
  }
@@ -243,12 +316,15 @@ export function useInteractionsStream(): InteractionsStreamState {
243
316
  return;
244
317
  }
245
318
  if (reconciling) seenInBacklog.add(interaction.interaction_id);
246
- // Dedupe by id; a redelivered add preserves the client answered flag so a
247
- // prior `answered` is not undone by an at-least-once replay.
319
+ // Dedupe by id; a redelivered add preserves the client answered flag (and
320
+ // its aging stamp) so a prior `answered` is not undone by an at-least-once
321
+ // replay. A fresh (pending) add carries no stamp until its answered frame.
248
322
  const existing = mapRef.current.get(interaction.interaction_id);
323
+ const answered = existing?.answered ?? false;
249
324
  mapRef.current.set(interaction.interaction_id, {
250
325
  ...interaction,
251
- answered: existing?.answered ?? false,
326
+ answered,
327
+ answeredAt: answered ? (existing?.answeredAt ?? null) : null,
252
328
  });
253
329
  publish();
254
330
  };