@springbrand/chat-client 0.1.3-alpha.12 → 0.1.3-alpha.15
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 +2 -2
- package/src/index.ts +1 -0
- package/src/use-universal-agent-chat.ts +71 -20
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@springbrand/chat-client",
|
|
3
|
-
"version": "0.1.3-alpha.
|
|
3
|
+
"version": "0.1.3-alpha.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"@types/react-dom": "^19.2.3",
|
|
26
26
|
"react-dom": "^19.2.7",
|
|
27
27
|
"typescript": "^7.0.2",
|
|
28
|
-
"@springbrand/agent-runtime": "0.2.0-alpha.
|
|
28
|
+
"@springbrand/agent-runtime": "0.2.0-alpha.22"
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
31
|
"typecheck": "tsc --noEmit"
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
createElement,
|
|
4
|
+
Suspense,
|
|
5
|
+
useCallback,
|
|
6
|
+
useContext,
|
|
7
|
+
useEffect,
|
|
8
|
+
useMemo,
|
|
9
|
+
useRef,
|
|
10
|
+
useState,
|
|
11
|
+
type ReactNode,
|
|
12
|
+
} from "react";
|
|
2
13
|
import { nanoid } from "nanoid";
|
|
3
14
|
import type { ChatStatus, FileUIPart, UIMessage } from "ai";
|
|
4
15
|
import type { AgentToolRunState } from "agents";
|
|
@@ -148,6 +159,8 @@ type SharedChatConnectionOptions = {
|
|
|
148
159
|
protocols?: string | string[];
|
|
149
160
|
inboxAgent?: string;
|
|
150
161
|
sessionAgent?: string;
|
|
162
|
+
/** Host projection used only until the selected Session sends its first state. */
|
|
163
|
+
initialTurnActive?: boolean;
|
|
151
164
|
};
|
|
152
165
|
|
|
153
166
|
export type ChatConnectionOptions = SharedChatConnectionOptions & (
|
|
@@ -155,6 +168,51 @@ export type ChatConnectionOptions = SharedChatConnectionOptions & (
|
|
|
155
168
|
| { inboxName?: never; basePath?: string }
|
|
156
169
|
);
|
|
157
170
|
|
|
171
|
+
type SessionAgentConnection = ReturnType<typeof useAgent<RuntimeState>>;
|
|
172
|
+
type UniversalAgentChatContextValue = {
|
|
173
|
+
chatId: string;
|
|
174
|
+
connection: ChatConnectionOptions;
|
|
175
|
+
agent: SessionAgentConnection;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const UniversalAgentChatContext = createContext<UniversalAgentChatContextValue | null>(null);
|
|
179
|
+
|
|
180
|
+
export function UniversalAgentChatProvider({
|
|
181
|
+
chatId,
|
|
182
|
+
connection = {},
|
|
183
|
+
fallback = null,
|
|
184
|
+
children,
|
|
185
|
+
}: {
|
|
186
|
+
chatId: string;
|
|
187
|
+
connection?: ChatConnectionOptions;
|
|
188
|
+
fallback?: ReactNode;
|
|
189
|
+
children: ReactNode;
|
|
190
|
+
}) {
|
|
191
|
+
const inboxAgent = connection.inboxAgent ?? "Inbox";
|
|
192
|
+
const agent = useAgent<RuntimeState>({
|
|
193
|
+
agent: inboxAgent,
|
|
194
|
+
...(connection.inboxName === undefined
|
|
195
|
+
? { basePath: connection.basePath ?? CURRENT_INBOX_AGENT_PATH }
|
|
196
|
+
: { name: connection.inboxName }),
|
|
197
|
+
...(connection.host === undefined ? {} : { host: connection.host }),
|
|
198
|
+
...(connection.protocols === undefined ? {} : { protocols: connection.protocols }),
|
|
199
|
+
connectionTimeout: 6_000,
|
|
200
|
+
sub: [{
|
|
201
|
+
agent: connection.sessionAgent ?? "UniversalAgent",
|
|
202
|
+
name: chatId,
|
|
203
|
+
}],
|
|
204
|
+
});
|
|
205
|
+
const value = useMemo(
|
|
206
|
+
() => ({ chatId, connection, agent }),
|
|
207
|
+
[agent, chatId, connection],
|
|
208
|
+
);
|
|
209
|
+
return createElement(
|
|
210
|
+
UniversalAgentChatContext.Provider,
|
|
211
|
+
{ value },
|
|
212
|
+
createElement(Suspense, { fallback }, children),
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
158
216
|
type ChatTurnTiming = {
|
|
159
217
|
chatId: string;
|
|
160
218
|
messageId: string;
|
|
@@ -282,10 +340,12 @@ function loadInitialMessages(
|
|
|
282
340
|
* sub 数组由客户端 kebab 化;服务端按 ctx.exports 反解回 CamelCase className,
|
|
283
341
|
* 与 Inbox.onBeforeSubAgent 的严格门卫(hasSubAgent)对齐。
|
|
284
342
|
*/
|
|
285
|
-
export function useUniversalAgentChat(
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
343
|
+
export function useUniversalAgentChat(): ChatRuntime {
|
|
344
|
+
const context = useContext(UniversalAgentChatContext);
|
|
345
|
+
if (!context) {
|
|
346
|
+
throw new Error("useUniversalAgentChat must be used within UniversalAgentChatProvider");
|
|
347
|
+
}
|
|
348
|
+
const { chatId, connection, agent } = context;
|
|
289
349
|
const [optimisticMessages, setOptimisticMessages] =
|
|
290
350
|
useState<ChatMessage[]>([]);
|
|
291
351
|
const [optimisticQueued, setOptimisticQueued] =
|
|
@@ -294,19 +354,6 @@ export function useUniversalAgentChat(
|
|
|
294
354
|
const [canRetry, setCanRetry] = useState(false);
|
|
295
355
|
const failedDispatchRef = useRef<FailedDispatch | undefined>(undefined);
|
|
296
356
|
const activeSubmissionIdRef = useRef<string | undefined>(undefined);
|
|
297
|
-
const inboxAgent = connection.inboxAgent ?? "Inbox";
|
|
298
|
-
const agent = useAgent<RuntimeState>({
|
|
299
|
-
agent: inboxAgent,
|
|
300
|
-
...(connection.inboxName === undefined
|
|
301
|
-
? { basePath: connection.basePath ?? CURRENT_INBOX_AGENT_PATH }
|
|
302
|
-
: { name: connection.inboxName }),
|
|
303
|
-
...(connection.host === undefined ? {} : { host: connection.host }),
|
|
304
|
-
...(connection.protocols === undefined ? {} : { protocols: connection.protocols }),
|
|
305
|
-
sub: [{
|
|
306
|
-
agent: connection.sessionAgent ?? "UniversalAgent",
|
|
307
|
-
name: chatId,
|
|
308
|
-
}],
|
|
309
|
-
});
|
|
310
357
|
const chatAgent = useMemo(
|
|
311
358
|
() => createSafeUIMessageAgentConnection(agent),
|
|
312
359
|
[agent],
|
|
@@ -384,9 +431,12 @@ export function useUniversalAgentChat(
|
|
|
384
431
|
? "streaming"
|
|
385
432
|
: "submitted"
|
|
386
433
|
: normalizedSdkStatus;
|
|
434
|
+
const hydratingTurnActive = facetState === undefined &&
|
|
435
|
+
connection.initialTurnActive === true;
|
|
387
436
|
const status = dispatchError
|
|
388
437
|
? "error"
|
|
389
|
-
: optimisticMessages.length > 0
|
|
438
|
+
: (optimisticMessages.length > 0 || hydratingTurnActive) &&
|
|
439
|
+
authoritativeStatus === "ready"
|
|
390
440
|
? "submitted"
|
|
391
441
|
: authoritativeStatus;
|
|
392
442
|
const messagesRef = useRef(messages);
|
|
@@ -478,7 +528,8 @@ export function useUniversalAgentChat(
|
|
|
478
528
|
isToolContinuation;
|
|
479
529
|
const pendingLocalTurn = optimisticMessages.length > 0 &&
|
|
480
530
|
(status === "submitted" || status === "streaming");
|
|
481
|
-
const turnActive =
|
|
531
|
+
const turnActive = hydratingTurnActive ||
|
|
532
|
+
Boolean(turn?.activeSubmissionId) ||
|
|
482
533
|
pendingLocalTurn ||
|
|
483
534
|
(authoritativeTurn === undefined && sdkTurnActive);
|
|
484
535
|
const canSteer = turnActive &&
|