@blade-hq/agent-react 2610.0.0-beta.31 → 2610.0.0-beta.33

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/README.md CHANGED
@@ -57,6 +57,7 @@ const client = useBladeClient() // 当前 Provider 的 BladeClient
57
57
  const { session, state, error } = useAgentSession(sessionId, {
58
58
  createOptions, // 不传 sessionId 时的建会话配置(UseAgentSessionOptions)
59
59
  onSessionCreated: (id) => saveSomewhere(id),
60
+ onSessionConnected: (session) => session.on("toolResult", handleResult),
60
61
  })
61
62
 
62
63
  state?.messages // ChatMessage[],直接渲染
@@ -70,8 +71,29 @@ await session?.send("你好")
70
71
 
71
72
  - 优先级:`sessionId`(连接既有会话)> `createOptions`(按配置新建)> 默认新建。
72
73
  - 自动创建只发生一次(含 React StrictMode 双跑);创建出的 id 通过 `onSessionCreated` 交还,重挂载时把它作为 `sessionId` 传回即可复用会话。
74
+ - 必须覆盖连接窗口内事件时,用 `onSessionConnected` 在历史加载和房间订阅开始前完成订阅,并返回取消订阅函数。
73
75
  - 同一 `sessionId` 的多次调用复用同一 `AgentSession` 实例(引用计数);卸载后延迟释放,路由抖动不会断连。
74
76
 
77
+ ## SessionMemoryToggle
78
+
79
+ 把当前会话是否使用记忆放进宿主自己的会话设置面板:
80
+
81
+ ```tsx
82
+ const [memoryEnabled, setMemoryEnabled] = useState(session.memory_enabled !== false)
83
+
84
+ <SessionMemoryToggle
85
+ sessionId={session.id}
86
+ enabled={memoryEnabled}
87
+ onSaved={(_sessionId, enabled) => setMemoryEnabled(enabled)}
88
+ onError={(error) => toast.error(String(error))}
89
+ />
90
+ ```
91
+
92
+ 组件默认使用 `BladeProvider` 的 client;已有独立 client 装配层的宿主也可以显式传
93
+ `client={client}`。同一 client、同一会话的多个开关共享保存锁,即使切换会话或同时存在多个
94
+ 设置入口,也不会并发提交相互覆盖。服务端确认后的权威值通过 `onSaved` 返回。
95
+ 全部属性见 `SessionMemoryToggleProps`。
96
+
75
97
  ## useReplay
76
98
 
77
99
  会话回放(演示 / 彩排):拿一个已经聊完的会话当素材,重现当时的回复和工具调用,
@@ -156,6 +178,11 @@ await replay.exitToAutonomous() // 退出回放,之后真的运
156
178
 
157
179
  全部 props 见 `ChatViewProps`。样式说明:
158
180
 
181
+ 智能体调用 `update_plan` 新增或更新任务时,`ChatView` 会在输入框上方自动展开最新任务进度,
182
+ 5 秒后平滑收起;连续更新会重新计时,用户手动展开或收起后以用户选择为准。自建聊天布局可直接
183
+ 使用 `CurrentPlanPanel` / `PlanUpdateBlock`,或用 `getPlanUpdateDisplayState`、
184
+ `parsePlanUpdate` 和 `pickCurrentPlanStep` 复用同一套判定。
185
+
159
186
  `ChatView` 的普通展示模式不显示只供诊断的项目说明、可用能力和当前工作环境。需要自建诊断界面时,可直接使用独立的 `ContextCard`,属性见 `ContextCardProps`;状态到文案的映射来自 agent-client 的 `getContextDisplayState`,不需要接入方重复判断。一次输入通常会同时注入十几项上下文,把渲染序列里连续的几项用 `ContextGroupCard`(属性见 `ContextGroupCardProps`)折成一行更合适;哪几项算一组由 agent-client 的 `groupAdjacentContextRuns` 判定,折叠行文案来自 `getContextGroupDisplayState` / `ContextGroupDisplayState`。底层数据类型为 `ContextProjectionData` / `ContextProjectionFields`,展示结果为 `ContextDisplayState`,并保留 `ContextAction`、`ContextSourceInfo` 和 `contextProjectionData` 给 headless 消费方。
160
187
 
161
188
  记忆引用提示可通过 `MemoryRefsHint` 展示,`collectMemoryRefs` 用于从一轮消息中聚合引用,保证宿主自定义消息布局与 SDK 默认界面保持一致。
@@ -356,4 +383,4 @@ blade-chat { --primary: 262 83% 58%; height: 640px; }
356
383
 
357
384
  为方便单包引入,本包 re-export 了 agent-client 的全部公开声明(`BladeClient`、`AgentSession`、`SessionState`、协议类型等),文档一律见 [agent-client 的 README](../agent-client/README.md)。完整签名见 [public-api.md](./public-api.md)。
358
385
 
359
- 本包自有声明:`BladeProvider`、`BladeProviderProps`、`useBladeClient`、`useAgentSession`、`UseAgentSessionOptions`、`UseAgentSessionResult`、`useMessagePin`、`UseMessagePinOptions`、`useReplay`、`UseReplayResult`、`ReplayMismatch`、`ReplayBar`、`ReplayBarProps`、`ReplayMismatchPrompt`、`ReplayMismatchPromptProps`、`ChatView`、`ChatViewProps`、`ChatViewClassNames`、`ChatViewRenderers`、`ChatViewSlots`、`FollowupInteractionEvent`、`ToolCallRenderer`、`MarkdownContent`、`MarkdownContentProps`、`parseWhatIfPrompt`、`ParsedWhatIfPrompt`、`WhatIfQuote`、`WhatIfUserBubble`、`WhatIfUserBubbleProps`。
386
+ 本包自有声明:`BladeProvider`、`BladeProviderProps`、`useBladeClient`、`useAgentSession`、`UseAgentSessionOptions`、`UseAgentSessionResult`、`useMessagePin`、`UseMessagePinOptions`、`useReplay`、`UseReplayResult`、`ReplayMismatch`、`ReplayBar`、`ReplayBarProps`、`ReplayMismatchPrompt`、`ReplayMismatchPromptProps`、`ChatView`、`ChatViewProps`、`ChatViewClassNames`、`ChatViewRenderers`、`ChatViewSlots`、`FollowupInteractionEvent`、`ToolCallRenderer`、`CurrentPlanPanel`、`PlanUpdateBlock`、`PlanUpdateData`、`PlanUpdateDisplayState`、`PlanStepStatus`、`getPlanUpdateDisplayState`、`isPlanUpdateTool`、`parsePlanUpdate`、`pickCurrentPlanStep`、`PLAN_AUTO_COLLAPSE_MS`、`MarkdownContent`、`MarkdownContentProps`、`parseWhatIfPrompt`、`ParsedWhatIfPrompt`、`WhatIfQuote`、`WhatIfUserBubble`、`WhatIfUserBubbleProps`。
@@ -7,6 +7,8 @@ interface Props {
7
7
  onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void;
8
8
  sessionStatus?: string;
9
9
  toolCallRenderer?: ToolCallRenderer;
10
+ /** Agent 模式把 update_plan 收口到输入框上方的任务面板;纯 LLM 同名工具照常展示。 */
11
+ hidePlanUpdateTools?: boolean;
10
12
  /** 会话 id;传给 Markdown 渲染的统一上下文。 */
11
13
  sessionId?: string;
12
14
  }
@@ -22,7 +24,7 @@ export declare function getExecutionDurationMs({ messages, isStreaming, now, }:
22
24
  now?: number;
23
25
  }): number;
24
26
  /** 一轮助手回复:执行过程默认折叠,最终正文始终显示在摘要下方。 */
25
- export declare function AssistantTurnBlock({ messages, isStreaming, askAnswers, onAnswer, sessionStatus, toolCallRenderer, sessionId, }: Props): import("react/jsx-runtime").JSX.Element;
27
+ export declare function AssistantTurnBlock({ messages, isStreaming, askAnswers, onAnswer, sessionStatus, toolCallRenderer, hidePlanUpdateTools, sessionId, }: Props): import("react/jsx-runtime").JSX.Element;
26
28
  export declare function collectMemoryRefs(messages: ChatMessage[]): MemoryRefInfo[];
27
29
  export declare function MemoryRefsHint({ refs }: {
28
30
  refs: MemoryRefInfo[];
@@ -55,6 +55,10 @@ interface ChatSurfaceProps extends ChatPresentationProps {
55
55
  onResultFeedbackSaved?: (feedback: ResultFeedback) => void;
56
56
  /** 输入框上方的内部区域(纯 LLM 模式的高级设置用)。不传时不渲染任何节点。 */
57
57
  beforeInput?: ReactNode;
58
+ /** 仅 Agent 模式启用 Blade 的 update_plan 面板。 */
59
+ showPlanUpdates?: boolean;
60
+ /** 仅实时成功的 update_plan 递增;历史 hydration 不得改变。 */
61
+ planRevealRevision?: number;
58
62
  /** 连接状态条下方的横幅(回放模式条用)。不传时不渲染任何节点。 */
59
63
  banner?: ReactNode;
60
64
  }
@@ -64,5 +68,5 @@ interface ChatSurfaceProps extends ChatPresentationProps {
64
68
  * 这里的 DOM 结构受 tests/chat-view-compat.test.tsx 的快照保护——接入方拿
65
69
  * .blade-chat-* 类名写了自己的样式,结构一动他们的页面就歪。
66
70
  */
67
- export declare function ChatSurface({ theme, classNames, renderers, slots, placeholder, connection, errorMessage, messages, postChatFollowup, isStreaming, isStopping, inputText, onInputChange, onSuggestion, onSend, onStop, sessionStatus, askAnswers, onAnswer, sessionId, isViewer, resultFeedbackByEntry, onResultFeedbackSaved, onFollowupInteraction, beforeInput, banner, }: ChatSurfaceProps): import("react/jsx-runtime").JSX.Element;
71
+ export declare function ChatSurface({ theme, classNames, renderers, slots, placeholder, connection, errorMessage, messages, postChatFollowup, isStreaming, isStopping, inputText, onInputChange, onSuggestion, onSend, onStop, sessionStatus, askAnswers, onAnswer, sessionId, isViewer, resultFeedbackByEntry, onResultFeedbackSaved, onFollowupInteraction, beforeInput, showPlanUpdates, planRevealRevision, banner, }: ChatSurfaceProps): import("react/jsx-runtime").JSX.Element;
68
72
  export {};
@@ -11,6 +11,7 @@ interface Props {
11
11
  askAnswers?: Record<string, AskUserAnswerData>;
12
12
  onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void;
13
13
  toolCallRenderer?: ToolCallRenderer;
14
+ hidePlanUpdateTools?: boolean;
14
15
  emptyState?: ReactNode;
15
16
  className?: string;
16
17
  /** 会话 id;传给助手消息的统一上下文。 */
@@ -24,5 +25,5 @@ interface Props {
24
25
  * 消息列表:use-stick-to-bottom 自动滚动 + 按轮次分组渲染。
25
26
  * 相比第一方版本去掉了轮次导航栏、吸顶状态条与规划摘要卡片。
26
27
  */
27
- export declare function MessageList({ messages, postChatFollowup, onSuggestion, isStreaming, sessionStatus, askAnswers, onAnswer, toolCallRenderer, emptyState, className, sessionId, isViewer, onFollowupInteraction, resultFeedbackByEntry, onResultFeedbackSaved, }: Props): import("react/jsx-runtime").JSX.Element;
28
+ export declare function MessageList({ messages, postChatFollowup, onSuggestion, isStreaming, sessionStatus, askAnswers, onAnswer, toolCallRenderer, hidePlanUpdateTools, emptyState, className, sessionId, isViewer, onFollowupInteraction, resultFeedbackByEntry, onResultFeedbackSaved, }: Props): import("react/jsx-runtime").JSX.Element;
28
29
  export {};
@@ -0,0 +1,31 @@
1
+ import type { ChatMessage, ToolCallInfo } from "@blade-hq/agent-client";
2
+ export type PlanStepStatus = "pending" | "in_progress" | "completed";
3
+ export interface PlanUpdateData {
4
+ plan: Array<{
5
+ step: string;
6
+ status: PlanStepStatus;
7
+ }>;
8
+ }
9
+ export declare const PLAN_AUTO_COLLAPSE_MS = 5000;
10
+ export declare function isPlanUpdateTool(toolCall: Pick<ToolCallInfo, "name">): boolean;
11
+ export interface PlanUpdateDisplayState {
12
+ current: ToolCallInfo | null;
13
+ updating: boolean;
14
+ }
15
+ export declare function getPlanUpdateDisplayState(messages: ChatMessage[]): PlanUpdateDisplayState;
16
+ export declare function parsePlanUpdate(argumentsJson: string): PlanUpdateData | null;
17
+ export declare function pickCurrentPlanStep(plan: PlanUpdateData["plan"]): PlanUpdateData["plan"][number] | null;
18
+ export declare function PlanUpdateBlock({ toolCall, running, autoReveal, }: {
19
+ toolCall: ToolCallInfo;
20
+ running?: boolean;
21
+ /** 实时收到的新进度短暂展开;加载历史时保持默认收起。 */
22
+ autoReveal?: boolean;
23
+ }): import("react/jsx-runtime").JSX.Element | null;
24
+ export declare function CurrentPlanPanel({ messages, running, revealRevision, sessionId, className, }: {
25
+ messages: ChatMessage[];
26
+ running?: boolean;
27
+ /** 仅实时成功的 update_plan 递增;历史 hydration 不得改变。 */
28
+ revealRevision?: number;
29
+ sessionId?: string;
30
+ className?: string;
31
+ }): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,19 @@
1
+ import type { BladeClient } from "@blade-hq/agent-client";
2
+ export interface SessionMemoryToggleProps {
3
+ sessionId: string;
4
+ enabled: boolean;
5
+ /** 不在 BladeProvider 内使用时显式传入,与宿主现有 BladeClient 复用连接和鉴权。 */
6
+ client?: BladeClient;
7
+ disabled?: boolean;
8
+ label?: string;
9
+ className?: string;
10
+ labelClassName?: string;
11
+ inputClassName?: string;
12
+ onSaved?: (sessionId: string, enabled: boolean) => void;
13
+ onError?: (error: unknown) => void;
14
+ }
15
+ /**
16
+ * 当前会话记忆开关。同一 client + sessionId 的所有实例共享保存锁,避免多个聊天入口
17
+ * 或会话切换时发出乱序更新;服务端成功后才通过 onSaved 交还权威值。
18
+ */
19
+ export declare function SessionMemoryToggle({ sessionId, enabled, client: clientProp, disabled, label, className, labelClassName, inputClassName, onSaved, onError, }: SessionMemoryToggleProps): import("react/jsx-runtime").JSX.Element;
package/dist/context.d.ts CHANGED
@@ -11,3 +11,4 @@ export interface BladeProviderProps {
11
11
  export declare function BladeProvider({ client, children }: BladeProviderProps): import("react/jsx-runtime").JSX.Element;
12
12
  /** 读取当前 BladeProvider 提供的 client。不在 Provider 内使用时抛错。 */
13
13
  export declare function useBladeClient(): BladeClient;
14
+ export declare function useOptionalBladeClient(): BladeClient | null;
@@ -4,6 +4,11 @@ export interface UseAgentSessionOptions {
4
4
  createOptions?: CreateSessionRequest;
5
5
  /** 自动创建出的 sessionId 通过此回调交还调用方持有(重挂载复用的依据)。 */
6
6
  onSessionCreated?: (sessionId: string) => void;
7
+ /**
8
+ * 会话进入实时事件路由后、历史加载与房间订阅开始前同步执行。
9
+ * 返回的清理函数会在切换会话或卸载时执行。
10
+ */
11
+ onSessionConnected?: (session: AgentSession) => () => void;
7
12
  }
8
13
  export interface UseAgentSessionResult {
9
14
  /** 连接/创建完成前为 null。 */
package/dist/index.d.ts CHANGED
@@ -27,9 +27,13 @@ export type { ReplayBarProps } from "./components/ReplayBar";
27
27
  export { ReplayMismatchPrompt } from "./components/ReplayMismatchPrompt";
28
28
  export type { ReplayMismatchPromptProps } from "./components/ReplayMismatchPrompt";
29
29
  export type { ToolCallRenderer } from "./components/ToolCallBlock";
30
+ export { CurrentPlanPanel, getPlanUpdateDisplayState, isPlanUpdateTool, PLAN_AUTO_COLLAPSE_MS, parsePlanUpdate, pickCurrentPlanStep, PlanUpdateBlock, } from "./components/PlanUpdateBlock";
31
+ export type { PlanStepStatus, PlanUpdateData, PlanUpdateDisplayState, } from "./components/PlanUpdateBlock";
30
32
  export { ContextCard, ContextGroupCard } from "./components/ContextCard";
31
33
  export type { ContextCardProps, ContextGroupCardProps } from "./components/ContextCard";
32
34
  export { collectMemoryRefs, MemoryRefsHint } from "./components/AssistantTurnBlock";
35
+ export { SessionMemoryToggle } from "./components/SessionMemoryToggle";
36
+ export type { SessionMemoryToggleProps } from "./components/SessionMemoryToggle";
33
37
  export { isAgentComputerCommand, isAgentComputerToolCall, classifyAgentComputerLaunchOutcome, } from "./lib/agent-computer-command";
34
38
  export type { AgentComputerLaunchOutcome } from "./lib/agent-computer-command";
35
39
  export * from "@blade-hq/agent-client";