@steerable/agent-ui 0.2.4 → 0.3.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.
@@ -26,6 +26,14 @@ export interface ChatStreamTransport {
26
26
  * call on unmount or when the user clicks "stop".
27
27
  */
28
28
  stream: (input: ChatStreamSendInput, onEvent: (event: SSEEvent) => void) => Promise<void | (() => void)>;
29
+ /**
30
+ * Optional mid-turn steering: inject a user message into the currently
31
+ * running turn (CoreLoop `steer`). Resolve `true` when the running turn
32
+ * accepted the message; `false` when no steerable turn is active (the
33
+ * caller should keep the draft — a normal send can follow once the turn
34
+ * ends). When omitted, the UI keeps send-during-streaming disabled.
35
+ */
36
+ steer?: (content: string) => Promise<boolean>;
29
37
  }
30
38
  export interface UseChatStreamOptions {
31
39
  /** Required transport handle; see `ChatStreamTransport`. */
@@ -48,7 +56,30 @@ export interface UseChatStreamOptions {
48
56
  export interface UseChatStreamReturn {
49
57
  messages: ChatMessage[];
50
58
  isStreaming: boolean;
59
+ /**
60
+ * Send a user message. Queue-safe (W6-2): if a turn is currently streaming
61
+ * the message is NOT dropped — it is appended to the follow-up queue and
62
+ * sent automatically as the next turn when the current one ends.
63
+ */
51
64
  sendUserMessage: (input: ChatStreamSendInput) => Promise<void>;
65
+ /**
66
+ * Steer the running turn with an extra user message. No-op resolving
67
+ * `false` when not streaming or the transport has no `steer`. On success
68
+ * the message is appended to the visible transcript immediately (the loop
69
+ * consumes it at the next round boundary).
70
+ */
71
+ steerUserMessage: (content: string) => Promise<boolean>;
72
+ /**
73
+ * Explicitly queue a message as a follow-up (W6-2): sent automatically as
74
+ * the next turn once the current turn finishes. When not streaming this is
75
+ * equivalent to `sendUserMessage`. Distinct from `steerUserMessage`, which
76
+ * redirects the *current* turn mid-flight.
77
+ */
78
+ followUpUserMessage: (input: ChatStreamSendInput) => void;
79
+ /** Follow-up messages queued while streaming, in order (not yet sent). */
80
+ pendingFollowUps: ChatStreamSendInput[];
81
+ /** Remove a queued follow-up by index (e.g. the user withdraws it). */
82
+ removeFollowUp: (index: number) => void;
52
83
  cancel: () => void;
53
84
  /** Replace the message buffer (e.g. when switching chat). */
54
85
  setMessages: (messages: ChatMessage[]) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useChatStream.d.ts","sourceRoot":"","sources":["../../src/hooks/useChatStream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EAER,UAAU,EACX,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,mBAAmB;IAClC,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;OAQG;IACH,MAAM,EAAE,CACN,KAAK,EAAE,mBAAmB,EAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,KAC/B,OAAO,CAAC,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,oBAAoB;IACnC,4DAA4D;IAC5D,SAAS,EAAE,mBAAmB,CAAC;IAC/B,+DAA+D;IAC/D,eAAe,CAAC,EAAE,WAAW,EAAE,CAAC;IAChC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,WAAW,GAAG,IAAI,CAAC;IACjE;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,6DAA6D;IAC7D,WAAW,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,IAAI,CAAC;IAC/C,mEAAmE;IACnE,aAAa,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CAC/C;AAsID,wBAAgB,aAAa,CAC3B,OAAO,EAAE,oBAAoB,GAC5B,mBAAmB,CAsIrB"}
1
+ {"version":3,"file":"useChatStream.d.ts","sourceRoot":"","sources":["../../src/hooks/useChatStream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EAER,UAAU,EACX,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,mBAAmB;IAClC,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;OAQG;IACH,MAAM,EAAE,CACN,KAAK,EAAE,mBAAmB,EAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,KAC/B,OAAO,CAAC,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IAClC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,oBAAoB;IACnC,4DAA4D;IAC5D,SAAS,EAAE,mBAAmB,CAAC;IAC/B,+DAA+D;IAC/D,eAAe,CAAC,EAAE,WAAW,EAAE,CAAC;IAChC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,WAAW,GAAG,IAAI,CAAC;IACjE;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,eAAe,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D;;;;;OAKG;IACH,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD;;;;;OAKG;IACH,mBAAmB,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC1D,0EAA0E;IAC1E,gBAAgB,EAAE,mBAAmB,EAAE,CAAC;IACxC,uEAAuE;IACvE,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,6DAA6D;IAC7D,WAAW,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,IAAI,CAAC;IAC/C,mEAAmE;IACnE,aAAa,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CAC/C;AAsID,wBAAgB,aAAa,CAC3B,OAAO,EAAE,oBAAoB,GAC5B,mBAAmB,CA+MrB"}
@@ -133,6 +133,14 @@ export function useChatStream(options) {
133
133
  const isStreamingRef = useRef(false);
134
134
  const cancelRef = useRef(null);
135
135
  const [, forceRerender] = useReducer((x) => x + 1, 0);
136
+ // W6-2 follow-up queue: messages submitted while a turn is streaming. Kept
137
+ // in a ref (drained imperatively at turn end) with a version counter to
138
+ // re-render consumers that show the pending queue.
139
+ const followUpsRef = useRef([]);
140
+ const [followUpVersion, bumpFollowUpVersion] = useReducer((x) => x + 1, 0);
141
+ // Self-handle so a finishing turn can start the next queued turn without a
142
+ // circular useCallback dependency.
143
+ const sendRef = useRef();
136
144
  const setStreaming = useCallback((next) => {
137
145
  isStreamingRef.current = next;
138
146
  forceRerender();
@@ -195,6 +203,10 @@ export function useChatStream(options) {
195
203
  }, [options]);
196
204
  const sendUserMessage = useCallback(async (input) => {
197
205
  if (isStreamingRef.current) {
206
+ // W6-2: queue instead of dropping. The finishing turn's `finally`
207
+ // drains the queue and starts the next turn automatically.
208
+ followUpsRef.current = [...followUpsRef.current, input];
209
+ bumpFollowUpVersion();
198
210
  return;
199
211
  }
200
212
  dispatch({ type: 'append', message: newUserMessage(input.content) });
@@ -216,15 +228,53 @@ export function useChatStream(options) {
216
228
  finally {
217
229
  cancelRef.current = null;
218
230
  setStreaming(false);
231
+ // W6-2: drain the follow-up queue — send the next queued message as
232
+ // a fresh turn. isStreamingRef is already false here, so the nested
233
+ // call starts a new turn rather than re-queueing.
234
+ const next = followUpsRef.current.shift();
235
+ if (next !== undefined) {
236
+ bumpFollowUpVersion();
237
+ void sendRef.current?.(next);
238
+ }
219
239
  }
220
240
  }, [handleEvent, options.transport, setStreaming]);
241
+ useEffect(() => {
242
+ sendRef.current = sendUserMessage;
243
+ }, [sendUserMessage]);
244
+ const followUpUserMessage = useCallback((input) => {
245
+ if (!isStreamingRef.current) {
246
+ void sendRef.current?.(input);
247
+ return;
248
+ }
249
+ followUpsRef.current = [...followUpsRef.current, input];
250
+ bumpFollowUpVersion();
251
+ }, []);
252
+ const removeFollowUp = useCallback((index) => {
253
+ followUpsRef.current = followUpsRef.current.filter((_, i) => i !== index);
254
+ bumpFollowUpVersion();
255
+ }, []);
221
256
  const cancel = useCallback(() => {
257
+ // Cancelling the current turn also drops queued follow-ups — an explicit
258
+ // stop means "don't keep going", so we don't auto-send what was queued.
259
+ followUpsRef.current = [];
260
+ bumpFollowUpVersion();
222
261
  if (cancelRef.current) {
223
262
  cancelRef.current();
224
263
  cancelRef.current = null;
225
264
  }
226
265
  setStreaming(false);
227
266
  }, [setStreaming]);
267
+ const steerUserMessage = useCallback(async (content) => {
268
+ const steer = options.transport.steer;
269
+ if (!isStreamingRef.current || !steer || !content.trim()) {
270
+ return false;
271
+ }
272
+ const ok = await steer(content);
273
+ if (ok) {
274
+ dispatch({ type: 'append', message: newUserMessage(content) });
275
+ }
276
+ return ok;
277
+ }, [options.transport]);
228
278
  const setMessages = useCallback((messages) => {
229
279
  dispatch({ type: 'reset', messages });
230
280
  }, []);
@@ -243,9 +293,26 @@ export function useChatStream(options) {
243
293
  messages: state.messages,
244
294
  isStreaming: isStreamingRef.current,
245
295
  sendUserMessage,
296
+ steerUserMessage,
297
+ followUpUserMessage,
298
+ // followUpVersion re-keys this memo so queue changes surface to the UI.
299
+ pendingFollowUps: followUpsRef.current,
300
+ removeFollowUp,
301
+ cancel,
302
+ setMessages,
303
+ appendMessage,
304
+ }),
305
+ // eslint-disable-next-line react-hooks/exhaustive-deps
306
+ [
307
+ state.messages,
308
+ sendUserMessage,
309
+ steerUserMessage,
310
+ followUpUserMessage,
311
+ removeFollowUp,
246
312
  cancel,
247
313
  setMessages,
248
314
  appendMessage,
249
- }), [state.messages, sendUserMessage, cancel, setMessages, appendMessage]);
315
+ followUpVersion,
316
+ ]);
250
317
  }
251
318
  //# sourceMappingURL=useChatStream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useChatStream.js","sourceRoot":"","sources":["../../src/hooks/useChatStream.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useChatStream.js","sourceRoot":"","sources":["../../src/hooks/useChatStream.ts"],"names":[],"mappings":"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"}
@@ -29,6 +29,7 @@ export interface ChatListTransport<TChat, TAgent> {
29
29
  listAgents: () => Promise<TAgent[]>;
30
30
  createChat?: (input: {
31
31
  agentId?: string;
32
+ projectId?: string;
32
33
  }) => Promise<TChat | string>;
33
34
  deleteChat?: (chatId: string) => Promise<boolean>;
34
35
  /** Tell the hook how to read a chat's id and title. */
@@ -62,6 +63,7 @@ export interface UseChatListReturn<TChat, TAgent> {
62
63
  loadMoreChats: () => Promise<void>;
63
64
  createChat: (input?: {
64
65
  agentId?: string;
66
+ projectId?: string;
65
67
  }) => Promise<string | null>;
66
68
  deleteChat: (chatId: string) => Promise<boolean>;
67
69
  /** In-place title patcher — does not hit the server. */
@@ -1 +1 @@
1
- {"version":3,"file":"useChatList.d.ts","sourceRoot":"","sources":["../../src/state/useChatList.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAML,KAAK,QAAQ,EACb,KAAK,cAAc,EACpB,MAAM,OAAO,CAAC;AAEf,MAAM,WAAW,iBAAiB,CAAC,KAAK,EAAE,MAAM;IAC9C,SAAS,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;QAChE,KAAK,EAAE,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC,CAAC;IACH,UAAU,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC;IACtE,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD,uDAAuD;IACvD,SAAS,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,MAAM,CAAC;IACnC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;IACrD,uEAAuE;IACvE,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB,CAAC,KAAK,EAAE,MAAM;IAC/C,SAAS,EAAE,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,sBAAsB;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB,CAAC,KAAK,EAAE,MAAM;IAC9C,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;;OAGG;IACH,kBAAkB,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC5D,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACrE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,wDAAwD;IACxD,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EACvC,OAAO,EAAE,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,GACzC,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CA2IlC"}
1
+ {"version":3,"file":"useChatList.d.ts","sourceRoot":"","sources":["../../src/state/useChatList.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAML,KAAK,QAAQ,EACb,KAAK,cAAc,EACpB,MAAM,OAAO,CAAC;AAEf,MAAM,WAAW,iBAAiB,CAAC,KAAK,EAAE,MAAM;IAC9C,SAAS,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;QAChE,KAAK,EAAE,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC,CAAC;IACH,UAAU,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC;IAC1F,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD,uDAAuD;IACvD,SAAS,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,MAAM,CAAC;IACnC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;IACrD,uEAAuE;IACvE,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB,CAAC,KAAK,EAAE,MAAM;IAC/C,SAAS,EAAE,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,sBAAsB;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB,CAAC,KAAK,EAAE,MAAM;IAC9C,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;;OAGG;IACH,kBAAkB,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC5D,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzF,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,wDAAwD;IACxD,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EACvC,OAAO,EAAE,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,GACzC,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CA8IlC"}
@@ -94,7 +94,10 @@ export function useChatList(options) {
94
94
  const t = transportRef.current;
95
95
  if (!t.createChat)
96
96
  return null;
97
- const created = await t.createChat({ agentId: input?.agentId ?? selectedAgentId ?? undefined });
97
+ const created = await t.createChat({
98
+ agentId: input?.agentId ?? selectedAgentId ?? undefined,
99
+ projectId: input?.projectId,
100
+ });
98
101
  // Either a chat object or a bare id.
99
102
  const id = typeof created === 'string' ? created : t.getChatId(created);
100
103
  await refreshChats();
@@ -1 +1 @@
1
- {"version":3,"file":"useChatList.js","sourceRoot":"","sources":["../../src/state/useChatList.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useChatList.js","sourceRoot":"","sources":["../../src/state/useChatList.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@steerable/agent-ui",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "Steerable framework Tier 4 — headless React hooks (useAgentSession, useChatStream, useToolCallStatus) and Tailwind-themed components (ChatPanel, MessageList, OrchestrationPlanCard, ToolCallRenderer, SSEStreamView) for embedding Steerable agents in any React app.",
5
5
  "license": "Apache-2.0",
6
- "homepage": "https://pathlyapp.github.io/steerable-framework/storybook/",
6
+ "homepage": "https://steerableframework.com/storybook/",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/pathlyapp/steerable-framework.git",
@@ -57,7 +57,7 @@
57
57
  "README.md"
58
58
  ],
59
59
  "dependencies": {
60
- "@steerable/agent-protocol": "0.2.4"
60
+ "@steerable/agent-protocol": "0.3.0"
61
61
  },
62
62
  "peerDependencies": {
63
63
  "react": ">=18.0.0",
@@ -12,9 +12,36 @@ import { describe, expect, it, vi } from 'vitest';
12
12
  import type { SSEEvent } from '@steerable/agent-protocol';
13
13
  import {
14
14
  useChatStream,
15
+ type ChatStreamSendInput,
15
16
  type ChatStreamTransport,
16
17
  } from './useChatStream';
17
18
 
19
+ /**
20
+ * A transport whose streams stay open until the test explicitly finishes them,
21
+ * so we can submit follow-ups mid-stream and watch the queue drain.
22
+ */
23
+ function makeControllableTransport() {
24
+ const streams: Array<{
25
+ input: ChatStreamSendInput;
26
+ onEvent: (e: SSEEvent) => void;
27
+ finish: () => void;
28
+ }> = [];
29
+ const transport: ChatStreamTransport = {
30
+ stream: (input, onEvent) =>
31
+ new Promise<void>((resolve) => {
32
+ streams.push({
33
+ input,
34
+ onEvent,
35
+ finish: () => {
36
+ onEvent({ type: 'done' });
37
+ resolve();
38
+ },
39
+ });
40
+ }),
41
+ };
42
+ return { transport, streams };
43
+ }
44
+
18
45
  function makeTransport(
19
46
  script: SSEEvent[][],
20
47
  ): { transport: ChatStreamTransport; cancel: ReturnType<typeof vi.fn> } {
@@ -231,3 +258,207 @@ describe('useChatStream', () => {
231
258
  expect(true).toBe(true);
232
259
  });
233
260
  });
261
+
262
+ describe('steerUserMessage', () => {
263
+ it('appends the user message when the transport accepts the steer', async () => {
264
+ const steer = vi.fn().mockResolvedValue(true);
265
+ const transport: ChatStreamTransport = {
266
+ stream: vi.fn(async (_input, onEvent) => {
267
+ onEvent({ type: 'content', content: 'working…' });
268
+ // keep the stream open until the test steers
269
+ await new Promise<void>((resolve) => setTimeout(resolve, 30));
270
+ onEvent({ type: 'content', content: 'done' });
271
+ onEvent({ type: 'done' });
272
+ }),
273
+ steer,
274
+ };
275
+ const { result } = renderHook(() => useChatStream({ transport }));
276
+
277
+ let done: Promise<void>;
278
+ act(() => {
279
+ done = result.current.sendUserMessage({ content: 'start' });
280
+ });
281
+ await act(async () => {
282
+ await new Promise((r) => setTimeout(r, 5));
283
+ });
284
+
285
+ let ok = false;
286
+ await act(async () => {
287
+ ok = await result.current.steerUserMessage('补充一句');
288
+ });
289
+ expect(ok).toBe(true);
290
+ expect(steer).toHaveBeenCalledWith('补充一句');
291
+ expect(
292
+ result.current.messages.some((m) => m.role === 'user' && m.content === '补充一句'),
293
+ ).toBe(true);
294
+
295
+ await act(async () => {
296
+ await done;
297
+ });
298
+ });
299
+
300
+ it('returns false and appends nothing when not streaming', async () => {
301
+ const steer = vi.fn().mockResolvedValue(true);
302
+ const transport: ChatStreamTransport = {
303
+ stream: vi.fn(async () => {}),
304
+ steer,
305
+ };
306
+ const { result } = renderHook(() => useChatStream({ transport }));
307
+
308
+ let ok = true;
309
+ await act(async () => {
310
+ ok = await result.current.steerUserMessage('hello');
311
+ });
312
+ expect(ok).toBe(false);
313
+ expect(steer).not.toHaveBeenCalled();
314
+ expect(result.current.messages).toHaveLength(0);
315
+ });
316
+
317
+ it('returns false when the transport has no steer support', async () => {
318
+ const transport: ChatStreamTransport = {
319
+ stream: vi.fn(async () => {
320
+ await new Promise<void>((resolve) => setTimeout(resolve, 20));
321
+ }),
322
+ };
323
+ const { result } = renderHook(() => useChatStream({ transport }));
324
+
325
+ let done: Promise<void>;
326
+ act(() => {
327
+ done = result.current.sendUserMessage({ content: 'start' });
328
+ });
329
+ let ok = true;
330
+ await act(async () => {
331
+ ok = await result.current.steerUserMessage('mid');
332
+ });
333
+ expect(ok).toBe(false);
334
+ await act(async () => {
335
+ await done;
336
+ });
337
+ });
338
+ });
339
+
340
+ describe('follow-up queue (W6-2)', () => {
341
+ it('sendUserMessage while streaming queues instead of dropping, then auto-sends next turn', async () => {
342
+ const { transport, streams } = makeControllableTransport();
343
+ const { result } = renderHook(() => useChatStream({ transport }));
344
+
345
+ // Turn 1 starts and stays open.
346
+ act(() => {
347
+ void result.current.sendUserMessage({ content: 'first' });
348
+ });
349
+ await waitFor(() => expect(streams).toHaveLength(1));
350
+ expect(result.current.isStreaming).toBe(true);
351
+
352
+ // Submit a second message mid-stream — must be queued, not dropped.
353
+ await act(async () => {
354
+ await result.current.sendUserMessage({ content: 'second' });
355
+ });
356
+ expect(streams).toHaveLength(1); // no new turn yet
357
+ expect(result.current.pendingFollowUps).toEqual([{ content: 'second' }]);
358
+
359
+ // Finish turn 1 → the queued message auto-sends as turn 2.
360
+ await act(async () => {
361
+ streams[0]!.finish();
362
+ });
363
+ await waitFor(() => expect(streams).toHaveLength(2));
364
+ expect(streams[1]!.input.content).toBe('second');
365
+ expect(result.current.pendingFollowUps).toEqual([]);
366
+
367
+ await act(async () => {
368
+ streams[1]!.finish();
369
+ });
370
+ await waitFor(() => expect(result.current.isStreaming).toBe(false));
371
+ // Both user messages landed in the transcript.
372
+ const userTexts = result.current.messages
373
+ .filter((m) => m.role === 'user')
374
+ .map((m) => m.content);
375
+ expect(userTexts).toEqual(['first', 'second']);
376
+ });
377
+
378
+ it('followUpUserMessage queues while streaming and sends immediately when idle', async () => {
379
+ const { transport, streams } = makeControllableTransport();
380
+ const { result } = renderHook(() => useChatStream({ transport }));
381
+
382
+ // Idle: followUpUserMessage behaves like a normal send.
383
+ await act(async () => {
384
+ result.current.followUpUserMessage({ content: 'idle' });
385
+ });
386
+ await waitFor(() => expect(streams).toHaveLength(1));
387
+ expect(streams[0]!.input.content).toBe('idle');
388
+
389
+ // Streaming: queues.
390
+ await act(async () => {
391
+ result.current.followUpUserMessage({ content: 'queued' });
392
+ });
393
+ expect(streams).toHaveLength(1);
394
+ expect(result.current.pendingFollowUps).toEqual([{ content: 'queued' }]);
395
+
396
+ await act(async () => {
397
+ streams[0]!.finish();
398
+ });
399
+ await waitFor(() => expect(streams).toHaveLength(2));
400
+ expect(streams[1]!.input.content).toBe('queued');
401
+ await act(async () => {
402
+ streams[1]!.finish();
403
+ });
404
+ });
405
+
406
+ it('removeFollowUp withdraws a queued message before it sends', async () => {
407
+ const { transport, streams } = makeControllableTransport();
408
+ const { result } = renderHook(() => useChatStream({ transport }));
409
+
410
+ act(() => {
411
+ void result.current.sendUserMessage({ content: 'first' });
412
+ });
413
+ await waitFor(() => expect(streams).toHaveLength(1));
414
+
415
+ await act(async () => {
416
+ result.current.followUpUserMessage({ content: 'keep' });
417
+ result.current.followUpUserMessage({ content: 'drop' });
418
+ });
419
+ expect(result.current.pendingFollowUps.map((m) => m.content)).toEqual(['keep', 'drop']);
420
+
421
+ await act(async () => {
422
+ result.current.removeFollowUp(1); // remove 'drop'
423
+ });
424
+ expect(result.current.pendingFollowUps.map((m) => m.content)).toEqual(['keep']);
425
+
426
+ await act(async () => {
427
+ streams[0]!.finish();
428
+ });
429
+ await waitFor(() => expect(streams).toHaveLength(2));
430
+ expect(streams[1]!.input.content).toBe('keep');
431
+ await act(async () => {
432
+ streams[1]!.finish();
433
+ });
434
+ // 'drop' never sent.
435
+ expect(streams).toHaveLength(2);
436
+ });
437
+
438
+ it('cancel() clears the queue so nothing auto-sends afterwards', async () => {
439
+ const { transport, streams } = makeControllableTransport();
440
+ const { result } = renderHook(() => useChatStream({ transport }));
441
+
442
+ act(() => {
443
+ void result.current.sendUserMessage({ content: 'first' });
444
+ });
445
+ await waitFor(() => expect(streams).toHaveLength(1));
446
+
447
+ await act(async () => {
448
+ result.current.followUpUserMessage({ content: 'queued' });
449
+ });
450
+ expect(result.current.pendingFollowUps).toHaveLength(1);
451
+
452
+ await act(async () => {
453
+ result.current.cancel();
454
+ });
455
+ expect(result.current.pendingFollowUps).toEqual([]);
456
+
457
+ // Even if the stream later finishes, no follow-up turn starts.
458
+ await act(async () => {
459
+ streams[0]!.finish();
460
+ });
461
+ await waitFor(() => expect(result.current.isStreaming).toBe(false));
462
+ expect(streams).toHaveLength(1);
463
+ });
464
+ });
@@ -38,6 +38,14 @@ export interface ChatStreamTransport {
38
38
  input: ChatStreamSendInput,
39
39
  onEvent: (event: SSEEvent) => void,
40
40
  ) => Promise<void | (() => void)>;
41
+ /**
42
+ * Optional mid-turn steering: inject a user message into the currently
43
+ * running turn (CoreLoop `steer`). Resolve `true` when the running turn
44
+ * accepted the message; `false` when no steerable turn is active (the
45
+ * caller should keep the draft — a normal send can follow once the turn
46
+ * ends). When omitted, the UI keeps send-during-streaming disabled.
47
+ */
48
+ steer?: (content: string) => Promise<boolean>;
41
49
  }
42
50
 
43
51
  export interface UseChatStreamOptions {
@@ -62,7 +70,30 @@ export interface UseChatStreamOptions {
62
70
  export interface UseChatStreamReturn {
63
71
  messages: ChatMessage[];
64
72
  isStreaming: boolean;
73
+ /**
74
+ * Send a user message. Queue-safe (W6-2): if a turn is currently streaming
75
+ * the message is NOT dropped — it is appended to the follow-up queue and
76
+ * sent automatically as the next turn when the current one ends.
77
+ */
65
78
  sendUserMessage: (input: ChatStreamSendInput) => Promise<void>;
79
+ /**
80
+ * Steer the running turn with an extra user message. No-op resolving
81
+ * `false` when not streaming or the transport has no `steer`. On success
82
+ * the message is appended to the visible transcript immediately (the loop
83
+ * consumes it at the next round boundary).
84
+ */
85
+ steerUserMessage: (content: string) => Promise<boolean>;
86
+ /**
87
+ * Explicitly queue a message as a follow-up (W6-2): sent automatically as
88
+ * the next turn once the current turn finishes. When not streaming this is
89
+ * equivalent to `sendUserMessage`. Distinct from `steerUserMessage`, which
90
+ * redirects the *current* turn mid-flight.
91
+ */
92
+ followUpUserMessage: (input: ChatStreamSendInput) => void;
93
+ /** Follow-up messages queued while streaming, in order (not yet sent). */
94
+ pendingFollowUps: ChatStreamSendInput[];
95
+ /** Remove a queued follow-up by index (e.g. the user withdraws it). */
96
+ removeFollowUp: (index: number) => void;
66
97
  cancel: () => void;
67
98
  /** Replace the message buffer (e.g. when switching chat). */
68
99
  setMessages: (messages: ChatMessage[]) => void;
@@ -211,6 +242,14 @@ export function useChatStream(
211
242
  const isStreamingRef = useRef(false);
212
243
  const cancelRef = useRef<(() => void) | null>(null);
213
244
  const [, forceRerender] = useReducer((x: number) => x + 1, 0);
245
+ // W6-2 follow-up queue: messages submitted while a turn is streaming. Kept
246
+ // in a ref (drained imperatively at turn end) with a version counter to
247
+ // re-render consumers that show the pending queue.
248
+ const followUpsRef = useRef<ChatStreamSendInput[]>([]);
249
+ const [followUpVersion, bumpFollowUpVersion] = useReducer((x: number) => x + 1, 0);
250
+ // Self-handle so a finishing turn can start the next queued turn without a
251
+ // circular useCallback dependency.
252
+ const sendRef = useRef<(input: ChatStreamSendInput) => Promise<void>>();
214
253
 
215
254
  const setStreaming = useCallback((next: boolean) => {
216
255
  isStreamingRef.current = next;
@@ -277,6 +316,10 @@ export function useChatStream(
277
316
  const sendUserMessage = useCallback(
278
317
  async (input: ChatStreamSendInput) => {
279
318
  if (isStreamingRef.current) {
319
+ // W6-2: queue instead of dropping. The finishing turn's `finally`
320
+ // drains the queue and starts the next turn automatically.
321
+ followUpsRef.current = [...followUpsRef.current, input];
322
+ bumpFollowUpVersion();
280
323
  return;
281
324
  }
282
325
  dispatch({ type: 'append', message: newUserMessage(input.content) });
@@ -297,12 +340,42 @@ export function useChatStream(
297
340
  } finally {
298
341
  cancelRef.current = null;
299
342
  setStreaming(false);
343
+ // W6-2: drain the follow-up queue — send the next queued message as
344
+ // a fresh turn. isStreamingRef is already false here, so the nested
345
+ // call starts a new turn rather than re-queueing.
346
+ const next = followUpsRef.current.shift();
347
+ if (next !== undefined) {
348
+ bumpFollowUpVersion();
349
+ void sendRef.current?.(next);
350
+ }
300
351
  }
301
352
  },
302
353
  [handleEvent, options.transport, setStreaming],
303
354
  );
304
355
 
356
+ useEffect(() => {
357
+ sendRef.current = sendUserMessage;
358
+ }, [sendUserMessage]);
359
+
360
+ const followUpUserMessage = useCallback((input: ChatStreamSendInput) => {
361
+ if (!isStreamingRef.current) {
362
+ void sendRef.current?.(input);
363
+ return;
364
+ }
365
+ followUpsRef.current = [...followUpsRef.current, input];
366
+ bumpFollowUpVersion();
367
+ }, []);
368
+
369
+ const removeFollowUp = useCallback((index: number) => {
370
+ followUpsRef.current = followUpsRef.current.filter((_, i) => i !== index);
371
+ bumpFollowUpVersion();
372
+ }, []);
373
+
305
374
  const cancel = useCallback(() => {
375
+ // Cancelling the current turn also drops queued follow-ups — an explicit
376
+ // stop means "don't keep going", so we don't auto-send what was queued.
377
+ followUpsRef.current = [];
378
+ bumpFollowUpVersion();
306
379
  if (cancelRef.current) {
307
380
  cancelRef.current();
308
381
  cancelRef.current = null;
@@ -310,6 +383,21 @@ export function useChatStream(
310
383
  setStreaming(false);
311
384
  }, [setStreaming]);
312
385
 
386
+ const steerUserMessage = useCallback(
387
+ async (content: string): Promise<boolean> => {
388
+ const steer = options.transport.steer;
389
+ if (!isStreamingRef.current || !steer || !content.trim()) {
390
+ return false;
391
+ }
392
+ const ok = await steer(content);
393
+ if (ok) {
394
+ dispatch({ type: 'append', message: newUserMessage(content) });
395
+ }
396
+ return ok;
397
+ },
398
+ [options.transport],
399
+ );
400
+
313
401
  const setMessages = useCallback((messages: ChatMessage[]) => {
314
402
  dispatch({ type: 'reset', messages });
315
403
  }, []);
@@ -332,10 +420,26 @@ export function useChatStream(
332
420
  messages: state.messages,
333
421
  isStreaming: isStreamingRef.current,
334
422
  sendUserMessage,
423
+ steerUserMessage,
424
+ followUpUserMessage,
425
+ // followUpVersion re-keys this memo so queue changes surface to the UI.
426
+ pendingFollowUps: followUpsRef.current,
427
+ removeFollowUp,
335
428
  cancel,
336
429
  setMessages,
337
430
  appendMessage,
338
431
  }),
339
- [state.messages, sendUserMessage, cancel, setMessages, appendMessage],
432
+ // eslint-disable-next-line react-hooks/exhaustive-deps
433
+ [
434
+ state.messages,
435
+ sendUserMessage,
436
+ steerUserMessage,
437
+ followUpUserMessage,
438
+ removeFollowUp,
439
+ cancel,
440
+ setMessages,
441
+ appendMessage,
442
+ followUpVersion,
443
+ ],
340
444
  );
341
445
  }
@@ -34,7 +34,7 @@ export interface ChatListTransport<TChat, TAgent> {
34
34
  hasMore: boolean;
35
35
  }>;
36
36
  listAgents: () => Promise<TAgent[]>;
37
- createChat?: (input: { agentId?: string }) => Promise<TChat | string>;
37
+ createChat?: (input: { agentId?: string; projectId?: string }) => Promise<TChat | string>;
38
38
  deleteChat?: (chatId: string) => Promise<boolean>;
39
39
  /** Tell the hook how to read a chat's id and title. */
40
40
  getChatId: (chat: TChat) => string;
@@ -67,7 +67,7 @@ export interface UseChatListReturn<TChat, TAgent> {
67
67
  refreshChats: () => Promise<void>;
68
68
  refreshAgents: () => Promise<void>;
69
69
  loadMoreChats: () => Promise<void>;
70
- createChat: (input?: { agentId?: string }) => Promise<string | null>;
70
+ createChat: (input?: { agentId?: string; projectId?: string }) => Promise<string | null>;
71
71
  deleteChat: (chatId: string) => Promise<boolean>;
72
72
  /** In-place title patcher — does not hit the server. */
73
73
  patchChatTitle: (chatId: string, title: string) => void;
@@ -140,10 +140,13 @@ export function useChatList<TChat, TAgent>(
140
140
  }, [hasMoreChats, isLoadingMoreChats, pageSize]);
141
141
 
142
142
  const createChat = useCallback(
143
- async (input?: { agentId?: string }) => {
143
+ async (input?: { agentId?: string; projectId?: string }) => {
144
144
  const t = transportRef.current;
145
145
  if (!t.createChat) return null;
146
- const created = await t.createChat({ agentId: input?.agentId ?? selectedAgentId ?? undefined });
146
+ const created = await t.createChat({
147
+ agentId: input?.agentId ?? selectedAgentId ?? undefined,
148
+ projectId: input?.projectId,
149
+ });
147
150
  // Either a chat object or a bare id.
148
151
  const id = typeof created === 'string' ? created : t.getChatId(created);
149
152
  await refreshChats();