@steerable/agent-ui 0.6.51 → 0.6.53
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.
|
@@ -94,8 +94,10 @@ export interface UseChatStreamReturn {
|
|
|
94
94
|
/**
|
|
95
95
|
* Steer the running turn with an extra user message. No-op resolving
|
|
96
96
|
* `false` when not streaming or the transport has no `steer`. On success
|
|
97
|
-
* the message is
|
|
98
|
-
*
|
|
97
|
+
* the message is inserted immediately before the in-flight assistant
|
|
98
|
+
* message, matching the persisted order (hosts store the steer at
|
|
99
|
+
* acceptance, the reply at turn end), so the streaming assistant stays the
|
|
100
|
+
* list tail. The loop consumes it at the next round boundary.
|
|
99
101
|
*/
|
|
100
102
|
steerUserMessage: (content: string) => Promise<boolean>;
|
|
101
103
|
/**
|
|
@@ -15,6 +15,14 @@ function reducer(state, action) {
|
|
|
15
15
|
return { messages: action.messages };
|
|
16
16
|
case 'append':
|
|
17
17
|
return { messages: [...state.messages, action.message] };
|
|
18
|
+
case 'insert-before-last-assistant': {
|
|
19
|
+
const idx = findLastAssistantIndex(state.messages);
|
|
20
|
+
if (idx === -1)
|
|
21
|
+
return { messages: [...state.messages, action.message] };
|
|
22
|
+
const next = state.messages.slice();
|
|
23
|
+
next.splice(idx, 0, action.message);
|
|
24
|
+
return { messages: next };
|
|
25
|
+
}
|
|
18
26
|
case 'patch-last-assistant': {
|
|
19
27
|
const idx = findLastAssistantIndex(state.messages);
|
|
20
28
|
if (idx === -1)
|
|
@@ -286,7 +294,7 @@ export function useChatStream(options) {
|
|
|
286
294
|
}
|
|
287
295
|
const ok = await steer(content);
|
|
288
296
|
if (ok) {
|
|
289
|
-
dispatch({ type: '
|
|
297
|
+
dispatch({ type: 'insert-before-last-assistant', message: newUserMessage(content) });
|
|
290
298
|
}
|
|
291
299
|
return ok;
|
|
292
300
|
}, [options.transport]);
|
|
@@ -303,7 +311,7 @@ export function useChatStream(options) {
|
|
|
303
311
|
if (steer) {
|
|
304
312
|
const ok = await steer(content);
|
|
305
313
|
if (ok) {
|
|
306
|
-
dispatch({ type: '
|
|
314
|
+
dispatch({ type: 'insert-before-last-assistant', message: newUserMessage(content) });
|
|
307
315
|
return 'steered';
|
|
308
316
|
}
|
|
309
317
|
// The turn may have ended while the steer was in flight; its
|
|
@@ -19,10 +19,9 @@ export interface UseToolCallStatusOptions {
|
|
|
19
19
|
call: ToolCall;
|
|
20
20
|
result?: ToolResult;
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* `decide_tool_mode`.
|
|
22
|
+
* Mode declared for this tool. First-party tools set this from registration.
|
|
23
|
+
* When omitted, the hook falls back to a name-prefix table. That fallback
|
|
24
|
+
* is only for undeclared third-party names.
|
|
26
25
|
*/
|
|
27
26
|
mode?: ToolCallMode;
|
|
28
27
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@steerable/agent-ui",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.53",
|
|
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
6
|
"homepage": "https://steerableframework.com/storybook/",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"README.md"
|
|
58
58
|
],
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@steerable/agent-protocol": "0.6.
|
|
60
|
+
"@steerable/agent-protocol": "0.6.53"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
63
|
"react": ">=18.0.0",
|
|
@@ -384,9 +384,13 @@ describe('steerOrFollowUpUserMessage', () => {
|
|
|
384
384
|
outcome = await result.current.steerOrFollowUpUserMessage('补充一句');
|
|
385
385
|
});
|
|
386
386
|
expect(outcome).toBe('steered');
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
).
|
|
387
|
+
// Inserted before the in-flight assistant (matches the persisted order),
|
|
388
|
+
// so the streaming assistant stays the list tail.
|
|
389
|
+
expect(result.current.messages.map((m) => [m.role, m.content])).toEqual([
|
|
390
|
+
['user', 'start'],
|
|
391
|
+
['user', '补充一句'],
|
|
392
|
+
['assistant', ''],
|
|
393
|
+
]);
|
|
390
394
|
expect(result.current.pendingFollowUps).toEqual([]);
|
|
391
395
|
expect(streams).toHaveLength(1);
|
|
392
396
|
|
|
@@ -107,8 +107,10 @@ export interface UseChatStreamReturn {
|
|
|
107
107
|
/**
|
|
108
108
|
* Steer the running turn with an extra user message. No-op resolving
|
|
109
109
|
* `false` when not streaming or the transport has no `steer`. On success
|
|
110
|
-
* the message is
|
|
111
|
-
*
|
|
110
|
+
* the message is inserted immediately before the in-flight assistant
|
|
111
|
+
* message, matching the persisted order (hosts store the steer at
|
|
112
|
+
* acceptance, the reply at turn end), so the streaming assistant stays the
|
|
113
|
+
* list tail. The loop consumes it at the next round boundary.
|
|
112
114
|
*/
|
|
113
115
|
steerUserMessage: (content: string) => Promise<boolean>;
|
|
114
116
|
/**
|
|
@@ -142,6 +144,7 @@ export interface UseChatStreamReturn {
|
|
|
142
144
|
type Action =
|
|
143
145
|
| { type: 'reset'; messages: ChatMessage[] }
|
|
144
146
|
| { type: 'append'; message: ChatMessage }
|
|
147
|
+
| { type: 'insert-before-last-assistant'; message: ChatMessage }
|
|
145
148
|
| { type: 'patch-last-assistant'; patch: Partial<ChatMessage> }
|
|
146
149
|
| { type: 'append-content'; delta: string }
|
|
147
150
|
| { type: 'append-tool-call'; call: ToolCall }
|
|
@@ -158,6 +161,13 @@ function reducer(state: State, action: Action): State {
|
|
|
158
161
|
return { messages: action.messages };
|
|
159
162
|
case 'append':
|
|
160
163
|
return { messages: [...state.messages, action.message] };
|
|
164
|
+
case 'insert-before-last-assistant': {
|
|
165
|
+
const idx = findLastAssistantIndex(state.messages);
|
|
166
|
+
if (idx === -1) return { messages: [...state.messages, action.message] };
|
|
167
|
+
const next = state.messages.slice();
|
|
168
|
+
next.splice(idx, 0, action.message);
|
|
169
|
+
return { messages: next };
|
|
170
|
+
}
|
|
161
171
|
case 'patch-last-assistant': {
|
|
162
172
|
const idx = findLastAssistantIndex(state.messages);
|
|
163
173
|
if (idx === -1) return state;
|
|
@@ -453,7 +463,7 @@ export function useChatStream(
|
|
|
453
463
|
}
|
|
454
464
|
const ok = await steer(content);
|
|
455
465
|
if (ok) {
|
|
456
|
-
dispatch({ type: '
|
|
466
|
+
dispatch({ type: 'insert-before-last-assistant', message: newUserMessage(content) });
|
|
457
467
|
}
|
|
458
468
|
return ok;
|
|
459
469
|
},
|
|
@@ -474,7 +484,7 @@ export function useChatStream(
|
|
|
474
484
|
if (steer) {
|
|
475
485
|
const ok = await steer(content);
|
|
476
486
|
if (ok) {
|
|
477
|
-
dispatch({ type: '
|
|
487
|
+
dispatch({ type: 'insert-before-last-assistant', message: newUserMessage(content) });
|
|
478
488
|
return 'steered';
|
|
479
489
|
}
|
|
480
490
|
// The turn may have ended while the steer was in flight; its
|
|
@@ -32,10 +32,9 @@ export interface UseToolCallStatusOptions {
|
|
|
32
32
|
call: ToolCall;
|
|
33
33
|
result?: ToolResult;
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* `decide_tool_mode`.
|
|
35
|
+
* Mode declared for this tool. First-party tools set this from registration.
|
|
36
|
+
* When omitted, the hook falls back to a name-prefix table. That fallback
|
|
37
|
+
* is only for undeclared third-party names.
|
|
39
38
|
*/
|
|
40
39
|
mode?: ToolCallMode;
|
|
41
40
|
/**
|