@blade-hq/agent-react 2610.0.0-beta.30 → 2610.0.0-beta.32

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,6 +71,7 @@ await session?.send("你好")
70
71
 
71
72
  - 优先级:`sessionId`(连接既有会话)> `createOptions`(按配置新建)> 默认新建。
72
73
  - 自动创建只发生一次(含 React StrictMode 双跑);创建出的 id 通过 `onSessionCreated` 交还,重挂载时把它作为 `sessionId` 传回即可复用会话。
74
+ - 必须覆盖连接窗口内事件时,用 `onSessionConnected` 在历史加载和房间订阅开始前完成订阅,并返回取消订阅函数。
73
75
  - 同一 `sessionId` 的多次调用复用同一 `AgentSession` 实例(引用计数);卸载后延迟释放,路由抖动不会断连。
74
76
 
75
77
  ## useReplay
@@ -156,7 +158,12 @@ await replay.exitToAutonomous() // 退出回放,之后真的运
156
158
 
157
159
  全部 props 见 `ChatViewProps`。样式说明:
158
160
 
159
- `ChatView` 的普通展示模式不显示只供诊断的项目说明、可用能力和当前工作环境。需要自建诊断界面时,可直接使用独立的 `ContextCard`,属性见 `ContextCardProps`;状态到文案的映射来自 agent-client 的 `getContextDisplayState`,不需要接入方重复判断。底层数据类型为 `ContextProjectionData` / `ContextProjectionFields`,展示结果为 `ContextDisplayState`,并保留 `ContextAction`、`ContextSourceInfo` 和 `contextProjectionData` 给 headless 消费方。
161
+ 智能体调用 `update_plan` 新增或更新任务时,`ChatView` 会在输入框上方自动展开最新任务进度,
162
+ 5 秒后平滑收起;连续更新会重新计时,用户手动展开或收起后以用户选择为准。自建聊天布局可直接
163
+ 使用 `CurrentPlanPanel` / `PlanUpdateBlock`,或用 `getPlanUpdateDisplayState`、
164
+ `parsePlanUpdate` 和 `pickCurrentPlanStep` 复用同一套判定。
165
+
166
+ `ChatView` 的普通展示模式不显示只供诊断的项目说明、可用能力和当前工作环境。需要自建诊断界面时,可直接使用独立的 `ContextCard`,属性见 `ContextCardProps`;状态到文案的映射来自 agent-client 的 `getContextDisplayState`,不需要接入方重复判断。一次输入通常会同时注入十几项上下文,把渲染序列里连续的几项用 `ContextGroupCard`(属性见 `ContextGroupCardProps`)折成一行更合适;哪几项算一组由 agent-client 的 `groupAdjacentContextRuns` 判定,折叠行文案来自 `getContextGroupDisplayState` / `ContextGroupDisplayState`。底层数据类型为 `ContextProjectionData` / `ContextProjectionFields`,展示结果为 `ContextDisplayState`,并保留 `ContextAction`、`ContextSourceInfo` 和 `contextProjectionData` 给 headless 消费方。
160
167
 
161
168
  记忆引用提示可通过 `MemoryRefsHint` 展示,`collectMemoryRefs` 用于从一轮消息中聚合引用,保证宿主自定义消息布局与 SDK 默认界面保持一致。
162
169
 
@@ -272,6 +279,22 @@ models.filter((m) => m.serviceModelId)
272
279
  <MarkdownContent sessionId={sessionId}>{markdownText}</MarkdownContent>
273
280
  ```
274
281
 
282
+ `normalizeAdjacentUrlFormatting` 可在复用其他 Markdown 渲染器前,保护紧贴行内格式标记的 URL。
283
+
284
+ ## Canonical 引用消息
285
+
286
+ `ChatView` 会自动识别 ship-attack 会话中的 `[引用]` / `[用户输入]` canonical
287
+ 消息,并按原顺序展示引用来源、快照和用户输入。自建消息列表时可用
288
+ `parseWhatIfPrompt` 解析同一格式,再交给 `WhatIfUserBubble` 渲染;
289
+ `onQuoteClick` 可接入宿主的步骤跳转。
290
+
291
+ ```tsx
292
+ const parsed = parseWhatIfPrompt(messageText)
293
+ return parsed ? (
294
+ <WhatIfUserBubble parsed={parsed} onQuoteClick={jumpToStep} />
295
+ ) : null
296
+ ```
297
+
275
298
  ## isAgentComputerCommand / isAgentComputerToolCall / classifyAgentComputerLaunchOutcome
276
299
 
277
300
  判断智能体是否在沙盒里启动了通用 GUI 应用镜像(`computer launch`)——后端 blade-agent 通过 `computer` CLI 驱动一块虚拟屏幕运行任意 GUI 软件,这些函数用于自行接入方判断要不要展示对应的实时画面入口(比如自建一个类似「电脑镜像」的标签页)。当前 SDK 侧还没有内置这块 UI,只导出判定规则,避免各接入方重新猜一遍匹配逻辑。
@@ -340,4 +363,4 @@ blade-chat { --primary: 262 83% 58%; height: 640px; }
340
363
 
341
364
  为方便单包引入,本包 re-export 了 agent-client 的全部公开声明(`BladeClient`、`AgentSession`、`SessionState`、协议类型等),文档一律见 [agent-client 的 README](../agent-client/README.md)。完整签名见 [public-api.md](./public-api.md)。
342
365
 
343
- 本包自有声明:`BladeProvider`、`BladeProviderProps`、`useBladeClient`、`useAgentSession`、`UseAgentSessionOptions`、`UseAgentSessionResult`、`useMessagePin`、`UseMessagePinOptions`、`useReplay`、`UseReplayResult`、`ReplayMismatch`、`ReplayBar`、`ReplayBarProps`、`ReplayMismatchPrompt`、`ReplayMismatchPromptProps`、`ChatView`、`ChatViewProps`、`ChatViewClassNames`、`ChatViewRenderers`、`ChatViewSlots`、`FollowupInteractionEvent`、`ToolCallRenderer`、`MarkdownContent`、`MarkdownContentProps`。
366
+ 本包自有声明:`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 {};
@@ -5,3 +5,16 @@ export interface ContextCardProps {
5
5
  }
6
6
  /** Business-facing Context summary. Native details keeps every card collapsed by default. */
7
7
  export declare function ContextCard({ context, className }: ContextCardProps): import("react/jsx-runtime").JSX.Element;
8
+ export interface ContextGroupCardProps {
9
+ contexts: readonly ContextProjectionData[];
10
+ className?: string;
11
+ }
12
+ /**
13
+ * 一批上下文注入折叠成一行。会话首轮会一次注入十几个原子,一条一张卡片会把
14
+ * 真正的对话挤出屏幕。
15
+ *
16
+ * 单条和多条**共用同一个 details 外壳**,不在数量变化时切换组件:流式时第二条
17
+ * 到达会让这一行从单条变成多条,组件类型一换 React 就重挂 <details>,
18
+ * 用户刚展开的行会被收起来。同理,key 由调用方按组内第一条给,不能带数量。
19
+ */
20
+ export declare function ContextGroupCard({ contexts, className }: ContextGroupCardProps): import("react/jsx-runtime").JSX.Element | null;
@@ -1,3 +1,5 @@
1
+ /** Keep inline formatting markers from being consumed by URL autolinking. */
2
+ export declare function normalizeAdjacentUrlFormatting(value: string): string;
1
3
  export interface MarkdownContentProps {
2
4
  children: string;
3
5
  className?: string;
@@ -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;
@@ -11,7 +11,7 @@ interface UserMessageProps {
11
11
  message: UserChatMessage;
12
12
  className?: string;
13
13
  }
14
- /** 用户消息气泡:文本 + 图片/文件附件展示(不含第一方的预览弹窗与 what-if 徽章)。 */
14
+ /** 用户消息气泡:文本、canonical 引用消息与图片/文件附件。 */
15
15
  export declare function UserMessageBubble({ message, className }: UserMessageProps): import("react/jsx-runtime").JSX.Element;
16
16
  /** 错误消息:居中红色提示条。 */
17
17
  export declare function ErrorMessageBlock({ message, className, }: {
@@ -0,0 +1,7 @@
1
+ import type { ParsedWhatIfPrompt } from "../lib/whatif-prompt";
2
+ export interface WhatIfUserBubbleProps {
3
+ parsed: ParsedWhatIfPrompt;
4
+ onQuoteClick?: (stepNumber: number) => void;
5
+ }
6
+ /** SDK 与内置 Web 共用的 canonical 引用消息渲染。 */
7
+ export declare function WhatIfUserBubble({ parsed, onQuoteClick }: WhatIfUserBubbleProps): import("react/jsx-runtime").JSX.Element;
@@ -50,6 +50,8 @@ declare const BladeAgent: {
50
50
  transformSlashCommand: typeof agentClient.transformSlashCommand;
51
51
  contextProjectionData: typeof agentClient.contextProjectionData;
52
52
  getContextDisplayState: typeof agentClient.getContextDisplayState;
53
+ getContextGroupDisplayState: typeof agentClient.getContextGroupDisplayState;
54
+ groupAdjacentContextRuns: typeof agentClient.groupAdjacentContextRuns;
53
55
  latestPostChatFollowup: typeof agentClient.latestPostChatFollowup;
54
56
  DEFAULT_REPLAY_SPEED: agentClient.ReplaySpeed;
55
57
  SessionInfo: import("arktype/internal/variants/object.ts").ObjectType<{
@@ -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
@@ -16,14 +16,21 @@ export { LlmChat } from "./components/LlmChat";
16
16
  export type { LlmChatHandle, LlmChatProps } from "./components/LlmChat";
17
17
  export type { LlmAdvancedSettings, LlmOverride } from "./components/LlmAdvancedSettings";
18
18
  export { MarkdownContent } from "./components/MarkdownContent";
19
+ export { normalizeAdjacentUrlFormatting } from "./components/MarkdownContent";
19
20
  export type { MarkdownContentProps } from "./components/MarkdownContent";
21
+ export { WhatIfUserBubble } from "./components/WhatIfUserBubble";
22
+ export type { WhatIfUserBubbleProps } from "./components/WhatIfUserBubble";
23
+ export { parseWhatIfPrompt } from "./lib/whatif-prompt";
24
+ export type { ParsedWhatIfPrompt, WhatIfQuote } from "./lib/whatif-prompt";
20
25
  export { ReplayBar } from "./components/ReplayBar";
21
26
  export type { ReplayBarProps } from "./components/ReplayBar";
22
27
  export { ReplayMismatchPrompt } from "./components/ReplayMismatchPrompt";
23
28
  export type { ReplayMismatchPromptProps } from "./components/ReplayMismatchPrompt";
24
29
  export type { ToolCallRenderer } from "./components/ToolCallBlock";
25
- export { ContextCard } from "./components/ContextCard";
26
- export type { ContextCardProps } from "./components/ContextCard";
30
+ export { CurrentPlanPanel, getPlanUpdateDisplayState, isPlanUpdateTool, PLAN_AUTO_COLLAPSE_MS, parsePlanUpdate, pickCurrentPlanStep, PlanUpdateBlock, } from "./components/PlanUpdateBlock";
31
+ export type { PlanStepStatus, PlanUpdateData, PlanUpdateDisplayState, } from "./components/PlanUpdateBlock";
32
+ export { ContextCard, ContextGroupCard } from "./components/ContextCard";
33
+ export type { ContextCardProps, ContextGroupCardProps } from "./components/ContextCard";
27
34
  export { collectMemoryRefs, MemoryRefsHint } from "./components/AssistantTurnBlock";
28
35
  export { isAgentComputerCommand, isAgentComputerToolCall, classifyAgentComputerLaunchOutcome, } from "./lib/agent-computer-command";
29
36
  export type { AgentComputerLaunchOutcome } from "./lib/agent-computer-command";