@blade-hq/agent-react 2610.0.0-beta.7 → 2610.0.0-beta.71

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.
Files changed (64) hide show
  1. package/README.md +308 -8
  2. package/dist/chunk-G3PMV62Z.js +36 -0
  3. package/dist/{chunk-ZXXLY4RM.js → chunk-IA6J2NTB.js} +9 -32
  4. package/dist/{chunk-ZXXLY4RM.js.map → chunk-IA6J2NTB.js.map} +1 -1
  5. package/dist/components/AgentChat.d.ts +3 -0
  6. package/dist/components/AgentLoopBlock.d.ts +3 -5
  7. package/dist/components/AskUserQuestionBlock.d.ts +12 -1
  8. package/dist/components/AssistantTurnBlock.d.ts +26 -8
  9. package/dist/components/ChatInput.d.ts +21 -1
  10. package/dist/components/ChatSurface.d.ts +133 -2
  11. package/dist/components/ChatView.d.ts +1 -1
  12. package/dist/components/ConnectorPanel.d.ts +41 -0
  13. package/dist/components/ContextCard.d.ts +20 -0
  14. package/dist/components/MarkdownContent.d.ts +2 -0
  15. package/dist/components/McpAppCard.d.ts +14 -0
  16. package/dist/components/MessageList.d.ts +38 -4
  17. package/dist/components/PlanUpdateBlock.d.ts +32 -0
  18. package/dist/components/PluginConnectorList.d.ts +47 -0
  19. package/dist/components/PluginTriggerStack.d.ts +22 -0
  20. package/dist/components/PostChatFollowupBlock.d.ts +5 -1
  21. package/dist/components/SessionMemoryToggle.d.ts +19 -0
  22. package/dist/components/SessionPluginConfigDialog.d.ts +10 -0
  23. package/dist/components/SessionPluginConfigForm.d.ts +14 -0
  24. package/dist/components/SessionPluginIcon.d.ts +30 -0
  25. package/dist/components/SessionPluginSelector.d.ts +10 -0
  26. package/dist/components/SessionQueuePanel.d.ts +74 -0
  27. package/dist/components/ToolCallBlock.d.ts +9 -3
  28. package/dist/components/ToolUiCardView.d.ts +9 -0
  29. package/dist/components/TurnNavRail.d.ts +23 -0
  30. package/dist/components/UserMessageBubble.d.ts +7 -3
  31. package/dist/components/WhatIfUserBubble.d.ts +7 -0
  32. package/dist/components/connector-panel-types.d.ts +37 -0
  33. package/dist/components/display-utils.d.ts +10 -0
  34. package/dist/components/plugin-config-draft.d.ts +13 -0
  35. package/dist/components/plugin-config-schema.d.ts +6 -0
  36. package/dist/components/plugin-connector.d.ts +40 -0
  37. package/dist/components/queue-panel-adjacency.d.ts +1 -0
  38. package/dist/components/use-session-plugin-activation.d.ts +40 -0
  39. package/dist/context.d.ts +1 -0
  40. package/dist/embed/blade-chat-element.d.ts +4 -3
  41. package/dist/embed/entry.d.ts +48 -0
  42. package/dist/{highlighted-body-B3W2YXNL-YD7FAP6V.js → highlighted-body-B3W2YXNL-YF4GVJGP.js} +3 -2
  43. package/dist/{highlighted-body-B3W2YXNL-YD7FAP6V.js.map → highlighted-body-B3W2YXNL-YF4GVJGP.js.map} +1 -1
  44. package/dist/hooks/use-agent-session.d.ts +5 -0
  45. package/dist/hooks/use-message-pin.d.ts +28 -0
  46. package/dist/hooks/use-turn-navigation.d.ts +117 -0
  47. package/dist/hooks/use-typewriter-reveal.d.ts +32 -0
  48. package/dist/index.d.ts +49 -1
  49. package/dist/index.js +45645 -1787
  50. package/dist/index.js.map +1 -1
  51. package/dist/lib/agent-computer-command.d.ts +34 -0
  52. package/dist/lib/random-id.d.ts +10 -0
  53. package/dist/lib/utils.d.ts +17 -2
  54. package/dist/lib/whatif-prompt.d.ts +18 -0
  55. package/dist/mermaid-3ZIDBTTL-QL4YGD6I.js +9 -0
  56. package/dist/mermaid-3ZIDBTTL-QL4YGD6I.js.map +1 -0
  57. package/dist/style.css +488 -402
  58. package/dist/style.full.css +499 -406
  59. package/dist/webapi-W3IB5DO4.js +2481 -0
  60. package/dist/webapi-W3IB5DO4.js.map +1 -0
  61. package/package.json +2 -2
  62. package/public-api.md +1657 -76
  63. package/dist/mermaid-3ZIDBTTL-N7YKJ3SM.js +0 -8
  64. /package/dist/{mermaid-3ZIDBTTL-N7YKJ3SM.js.map → chunk-G3PMV62Z.js.map} +0 -0
@@ -0,0 +1,30 @@
1
+ import type { BladeClient, SessionPlugin } from "@blade-hq/agent-client";
2
+ export interface SessionPluginIconProps {
3
+ client: BladeClient;
4
+ /**
5
+ * 会话内已准备的包。传 `null` 时改用账号级目录图标(`/api/plugins/{name}/icon`),
6
+ * 这样首页这种还没有会话的地方也能显示包内图标。
7
+ */
8
+ sessionId: string | null;
9
+ plugin: Pick<SessionPlugin, "name" | "icon">;
10
+ /** 边长,默认 20。 */
11
+ size?: number;
12
+ /**
13
+ * 外框形状:`rounded`(默认,面板列表里的小方角)或 `circle`(触发器上的头像堆叠)。
14
+ * 默认值不动,避免改到列表与第三方接入方的观感。
15
+ */
16
+ shape?: "rounded" | "circle";
17
+ className?: string;
18
+ }
19
+ export interface SessionPluginLabelProps {
20
+ plugin: Pick<SessionPlugin, "name" | "display_name">;
21
+ }
22
+ /**
23
+ * Business name for a plugin, falling back to the technical ID.
24
+ *
25
+ * The ID stays authoritative for paths, authorization, caching and calls; this
26
+ * helper only decides what a user reads. Keep it shared — one place decides.
27
+ */
28
+ export declare function sessionPluginLabel(plugin: Pick<SessionPlugin, "name" | "display_name">): string;
29
+ /** Package-local plugin icon, with a stable generic placeholder. */
30
+ export declare function SessionPluginIcon({ client, sessionId, plugin, size, shape, className }: SessionPluginIconProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import type { BladeClient, SessionPluginActivation } from "@blade-hq/agent-client";
2
+ export interface SessionPluginSelectorProps {
3
+ client: BladeClient;
4
+ sessionId: string;
5
+ className?: string;
6
+ side?: "top" | "bottom";
7
+ onChange?: (plugin: SessionPluginActivation) => void;
8
+ }
9
+ /** Shared selector for AgentChat and the built-in Web; no external query provider required. */
10
+ export declare function SessionPluginSelector(props: SessionPluginSelectorProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,74 @@
1
+ import { type QueuedMessage, type SessionQueueSnapshot } from "@blade-hq/agent-client";
2
+ import { type JSX } from "react";
3
+ export interface SessionQueuePanelProps {
4
+ snapshot: SessionQueueSnapshot;
5
+ /** 当前是否有可接收补充的运行任务(决定「立刻发送」是否可用) */
6
+ canDeliver: boolean;
7
+ /** 正在等服务端确认的条目 id:禁用该条目的操作,避免重复提交 */
8
+ pendingItemId?: string | null;
9
+ /** 冲突/失败提示,例如「该消息已开始执行」;展示在面板顶部 */
10
+ notice?: string | null;
11
+ onResume: () => void;
12
+ onCancel: (item: QueuedMessage) => void;
13
+ onEdit: (item: QueuedMessage, content: string) => boolean | undefined | Promise<boolean>;
14
+ onRequeue?: (content: string) => Promise<boolean>;
15
+ onMove: (item: QueuedMessage, delta: -1 | 1) => void;
16
+ onReorder: (orderedIds: string[]) => void;
17
+ onDeliver: (item: QueuedMessage) => void;
18
+ /**
19
+ * 队列内容与外层留白的宽度类,要和下面输入框用同一个值。
20
+ *
21
+ * 队列卡片是"比输入框窄一圈、露在它上方"的形态,所以这里的宽度必须跟着
22
+ * 输入框走:输入框宽度由调用方决定(内置 Web 默认 max-w-3xl,软件工厂用
23
+ * `max-w-[748px]!` 覆盖,SDK 侧是 max-w-[748px])。写死一个值的话,两种
24
+ * 布局里总有一种对不齐——之前写死 max-w-[748px] 且外层 px-4,而输入框
25
+ * 外层是 px-5,软件工厂恰好都是 748 看着还行,普通聊天里输入框是 768,
26
+ * 队列连缩进一起窄了 22px。
27
+ */
28
+ contentWidthClassName?: string;
29
+ /** 根节点附加类。宿主用它在根上重设 `--blade-chat-queue-gutter`(或别的变量)。 */
30
+ rootClassName?: string;
31
+ /**
32
+ * 面板占位状态变化时回调(true = 正在占位)。
33
+ *
34
+ * 面板有本地 `editing` 状态:用户编辑到一半、那条等待消息被服务端拿走后,
35
+ * 面板仍要留在原地保住没保存的正文(见 `detachedEdit`)。这时 `items` 是空的,
36
+ * 光凭 snapshot 判不出面板还在,宿主就会把输入框上两角恢复成圆角、接缝上露出
37
+ * 尖角。让面板自己上报,宿主不必也无法复刻这个判据。
38
+ */
39
+ onVisibleChange?: (visible: boolean) => void;
40
+ /**
41
+ * 面板是否真的紧贴下面的输入框。
42
+ *
43
+ * 中间夹着别的内容时(MCP 暂存内容、内置 Web 的 `composerBanner`)两者并不
44
+ * 相接,这时面板下两角也要圆起来——直角是"被下面的输入框接住"的表示,露出
45
+ * 直角却下面空着一块,看起来像被削掉一角。
46
+ *
47
+ * 不传时读 context(见 `QueuePanelAdjacencyContext`):面板通常由宿主创建、
48
+ * 挂进 `ChatSurface`,而"中间有没有内容"是 `ChatSurface` 内部的 state,
49
+ * 宿主拿不到。内置 Web 自己管布局,直接把值传进来即可。
50
+ */
51
+ mergesWithInputBelow?: boolean;
52
+ }
53
+ /**
54
+ * 队列面板此刻会不会占位。
55
+ *
56
+ * 输入框要据此把自己的上两角改成直角:队列贴在它上方、而且比它窄一圈,
57
+ * 输入框上角若还是 22px 圆弧,那两段弧会从队列两侧露出来,形成两个尖角。
58
+ *
59
+ * 抽成一个函数而不是两边各判一次,是为了让"面板可见"和"输入框顶角改直角"
60
+ * 永远同步——这正是仓库里反复出现的"改了一个入口漏了另一个"。
61
+ * 传入的 `editing` 是面板自己的本地编辑态,默认 false。
62
+ */
63
+ export declare function isQueuePanelVisible(snapshot: Pick<SessionQueueSnapshot, "items" | "paused">, notice: string | null | undefined, editing?: boolean): boolean;
64
+ /**
65
+ * 会话消息队列面板:输入框上方的「待执行 · N」区域。
66
+ *
67
+ * 一行一条:左边三条横向的拖动手柄、中间单行截断的正文、右边 hover 才出现的操作
68
+ * (立刻发送 / 编辑 / 删除)。顺序靠拖动整行调整,手柄上也能用 Alt+↑/↓ 调(键盘
69
+ * 可达性不能因为去掉上下箭头按钮就没了)。
70
+ *
71
+ * 纯展示组件,不持有会话状态;能否编辑/删除/补充全部用 agent-client 的判定函数,
72
+ * 不在本包重写一份。拖动与键盘调整最终都由调用方提交完整的 pending id 顺序。
73
+ */
74
+ export declare function SessionQueuePanel({ snapshot, canDeliver, pendingItemId, notice, onResume, onCancel, onEdit, onRequeue, onMove, onReorder, onDeliver, contentWidthClassName, rootClassName, onVisibleChange, mergesWithInputBelow: mergesWithInputBelowProp, }: SessionQueuePanelProps): JSX.Element | null;
@@ -1,5 +1,6 @@
1
1
  import type { AskUserAnswerData, ToolCallInfo } from "@blade-hq/agent-client";
2
2
  import { type ReactNode } from "react";
3
+ import type { ChatViewClassNames, ChatViewRenderers } from "./ChatSurface";
3
4
  /** 接入方自定义渲染器:返回 null 时回落到默认渲染。 */
4
5
  export type ToolCallRenderer = (info: ToolCallInfo) => ReactNode | null;
5
6
  interface Props {
@@ -8,7 +9,11 @@ interface Props {
8
9
  answered?: boolean;
9
10
  answerData?: AskUserAnswerData;
10
11
  sessionStatus?: string;
11
- renderer?: ToolCallRenderer;
12
+ isActiveQuestion?: boolean;
13
+ /** 各可见区块的 className 落点;键与元素上的 `blade-chat-*` 锚点一一对应。 */
14
+ classNames?: ChatViewClassNames;
15
+ /** 区块级渲染器;返回 null 走默认渲染。 */
16
+ renderers?: ChatViewRenderers;
12
17
  }
13
18
  /**
14
19
  * 判断提问卡片该等待作答还是展示成已作答,只认工具状态。
@@ -19,10 +24,11 @@ interface Props {
19
24
  * 会同时把已经回答过的旧提问重新变成可作答(历史加载不会带回 answerData),
20
25
  * 而且会盖住投影层的错误——这个 bug 就是这么藏住的。
21
26
  */
22
- export declare function resolveAskQuestionState({ toolStatus, hasAnswerData, fallbackAnswered, }: {
27
+ export declare function resolveAskQuestionState({ toolStatus, hasAnswerData, fallbackAnswered, fallbackAwaiting, }: {
23
28
  toolStatus: ToolCallInfo["status"];
24
29
  hasAnswerData: boolean;
25
30
  fallbackAnswered?: boolean;
31
+ fallbackAwaiting?: boolean;
26
32
  }): {
27
33
  awaitingAnswer: boolean;
28
34
  answered: boolean;
@@ -31,5 +37,5 @@ export declare function resolveAskQuestionState({ toolStatus, hasAnswerData, fal
31
37
  * 极简工具调用块:状态 + 展示名一行,点开后是参数/结果的 <pre> 折叠展示。
32
38
  * AskUserQuestion 特殊处理为提问选项卡片。
33
39
  */
34
- export declare function ToolCallBlock({ toolCall, onAnswer, answered, answerData, sessionStatus, renderer, }: Props): import("react/jsx-runtime").JSX.Element;
40
+ export declare function ToolCallBlock({ toolCall, onAnswer, answered, answerData, sessionStatus, isActiveQuestion, classNames, renderers, }: Props): import("react/jsx-runtime").JSX.Element;
35
41
  export {};
@@ -0,0 +1,9 @@
1
+ import { type ToolUiCard } from "@blade-hq/agent-client";
2
+ /**
3
+ * MCP Apps 使用 SDK/Web 共享的 AppBridge;恢复只消费留档,不重读资源。
4
+ * 普通资源卡片仍使用 agent-client 的共享内容判定。
5
+ */
6
+ export declare function ToolUiCardView({ card, sessionId }: {
7
+ card: ToolUiCard;
8
+ sessionId?: string;
9
+ }): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,23 @@
1
+ import type { TurnNavItem } from "../hooks/use-turn-navigation";
2
+ export interface TurnNavRailProps {
3
+ /** 当前会话全部用户发言的目录;少于两条时不渲染(一条没有导航的意义)。 */
4
+ items: TurnNavItem[];
5
+ /** 正在高亮的那条发言(视口所在轮,或刚定位到的目标)。 */
6
+ activeTurnId: string | null;
7
+ /** 正在请求定位的目标;null 表示没有在途定位。 */
8
+ loadingTurnId?: string | null;
9
+ /** 定位失败提示。 */
10
+ error?: string | null;
11
+ /** 定位失败的那条发言;重试按钮就再点它一次。 */
12
+ failedTurnId?: string | null;
13
+ /** 点击/重试某条发言。 */
14
+ onSelectTurn: (entryId: string) => void;
15
+ }
16
+ /**
17
+ * 用户发言的刻度轨:右侧一列刻度,悬停/聚焦展开目录列表。
18
+ *
19
+ * 只负责显示和点击,请求、滚动与高亮全在 `useTurnNavigation` 里——内置 Web 那份
20
+ * rail(apps/web 的 TurnNavRail.tsx)有同样的语义,样式与交互各自实现。
21
+ * 类名走 `blade-turn-nav-*`:宿主没装 Tailwind 时 style.css 提供等效样式。
22
+ */
23
+ export declare function TurnNavRail({ items, activeTurnId, loadingTurnId, error, failedTurnId, onSelectTurn, }: TurnNavRailProps): import("react/jsx-runtime").JSX.Element | null;
@@ -1,4 +1,5 @@
1
1
  import type { ChatMessage } from "@blade-hq/agent-client";
2
+ import type { ChatViewClassNames, ChatViewRenderers } from "./ChatSurface";
2
3
  export type UserChatMessage = ChatMessage & {
3
4
  role: "user";
4
5
  };
@@ -9,10 +10,13 @@ export declare function isUserMessage(message: ChatMessage): message is UserChat
9
10
  export declare function isErrorMessage(message: ChatMessage): message is ErrorChatMessage;
10
11
  interface UserMessageProps {
11
12
  message: UserChatMessage;
12
- className?: string;
13
+ /** 各可见区块的 className 落点;键与元素上的 `blade-chat-*` 锚点一一对应。 */
14
+ classNames?: ChatViewClassNames;
15
+ /** 区块级渲染器;userMessage 只替换气泡本身,行与附件仍由 SDK 渲染。 */
16
+ renderers?: ChatViewRenderers;
13
17
  }
14
- /** 用户消息气泡:文本 + 图片/文件附件展示(不含第一方的预览弹窗与 what-if 徽章)。 */
15
- export declare function UserMessageBubble({ message, className }: UserMessageProps): import("react/jsx-runtime").JSX.Element;
18
+ /** 用户消息气泡:文本、canonical 引用消息与图片/文件附件。 */
19
+ export declare function UserMessageBubble({ message, classNames, renderers }: UserMessageProps): import("react/jsx-runtime").JSX.Element;
16
20
  /** 错误消息:居中红色提示条。 */
17
21
  export declare function ErrorMessageBlock({ message, className, }: {
18
22
  message: ErrorChatMessage;
@@ -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;
@@ -0,0 +1,37 @@
1
+ import type { PluginConnectorItem } from "./plugin-connector";
2
+ /**
3
+ * 首页选中的一个待选插件。
4
+ *
5
+ * 带上展示名和图标是为了两件事:后续的配置弹窗与失败提示能一直用业务名(只传技术
6
+ * ID 的话,用户在面板里看到「示例登录」、在弹窗标题里看到 `demo-login`,等于要他认
7
+ * 两遍),以及不用打开面板就能在触发器上看到自己选了什么。
8
+ *
9
+ * 技术 ID 仍是路径、授权、缓存与调用的权威。
10
+ */
11
+ export interface PluginConnectorSelection {
12
+ name: string;
13
+ displayName: string | null;
14
+ icon: string | null;
15
+ iconSource: PluginConnectorItem["iconSource"];
16
+ }
17
+ /** 面板一行 → 待选条目。 */
18
+ export declare function selectionFromItem(item: PluginConnectorItem): PluginConnectorSelection;
19
+ /** 触发器上最多直接显示几个插件头像,其余折成数量。 */
20
+ export declare const TRIGGER_ICON_LIMIT = 3;
21
+ /** 触发器上的头像堆叠内容:前三个 + 折起来的数量。 */
22
+ export interface TriggerSummary {
23
+ /** 前 TRIGGER_ICON_LIMIT 个选中项,**不管有没有图标 token**。 */
24
+ visible: Array<Pick<PluginConnectorSelection, "name" | "displayName" | "icon" | "iconSource">>;
25
+ /** 超出 TRIGGER_ICON_LIMIT 的数量;0 表示不显示 `+N`。 */
26
+ overflow: number;
27
+ /** 已选/已启用的总数,用于无障碍标签与提示。 */
28
+ total: number;
29
+ }
30
+ /**
31
+ * 把一份插件列表折成触发器上的头像堆叠。
32
+ *
33
+ * 前三项都占位,**不管有没有图标 token**:没有图标的用显示名首字起头的圆形占位,
34
+ * 「选了哪个」照样看得见。早先的实现把无图标的项从图标位里剔掉、还把它们算进
35
+ * `overflow`,于是选中一个没有图标的插件时触发器毫无变化——选择在入口上不可见。
36
+ */
37
+ export declare function triggerSummary(items: Array<Pick<PluginConnectorSelection, "name" | "displayName" | "icon" | "iconSource">>): TriggerSummary;
@@ -1,7 +1,17 @@
1
1
  import type { ToolCallInfo } from "@blade-hq/agent-client";
2
2
  export type ToolTone = "emerald" | "blue" | "amber" | "red";
3
+ /**
4
+ * 技能入口文件的所在目录就是技能名(`.agent/skills/<技能名>/SKILL.md`)。
5
+ * 只显示 "SKILL.md" 用户看不出读的是哪个技能。
6
+ *
7
+ * 改这里必须同步 apps/web/src/agent/components/chat/display-utils.ts 的同名函数。
8
+ */
9
+ export declare function getSkillNameFromFilePath(filePath: string | null | undefined): string | null;
3
10
  /** 归一化工具名:去掉命名空间前缀并映射到别名表(如 "fork:Agent" → "Agent")。 */
4
11
  export declare function formatToolName(name: string): string;
12
+ export declare function extractToolFilePath(toolCall: ToolCallInfo): string | null;
13
+ /** 从文件类工具参数中提取全部可定位的文件路径(按出现顺序去重)。 */
14
+ export declare function extractToolFilePaths(toolCall: ToolCallInfo): string[];
5
15
  /**
6
16
  * 返回工具调用的中文展示标签:优先取参数里的 description,
7
17
  * 其次取后端下发的 display_name / 系统工具中文名。
@@ -0,0 +1,13 @@
1
+ import type { SessionPluginConfigSet, SessionPluginConfigState } from "@blade-hq/agent-client";
2
+ export type ConfigPath = (string | number)[];
3
+ export type ConfigValues = Record<string, unknown>;
4
+ export declare function createConfigDraft(config: SessionPluginConfigState): {
5
+ values: ConfigValues;
6
+ retained: Map<string, string>;
7
+ };
8
+ /** Array edits address the original indices because the API applies sets before removals. */
9
+ export declare function originalConfigPath(path: ConfigPath, removed: Set<string>): ConfigPath;
10
+ export declare function configDraftOperations(initial: ConfigValues, values: ConfigValues, retained: Map<string, string>, removed: Set<string>): {
11
+ set: SessionPluginConfigSet[];
12
+ remove: string[];
13
+ };
@@ -0,0 +1,6 @@
1
+ import type { SessionPluginConfigState } from "@blade-hq/agent-client";
2
+ export type JsonSchema = Record<string, unknown>;
3
+ export declare function pointerOf(parts: (string | number)[]): string;
4
+ export declare function pointerParts(pointer: string): string[];
5
+ export declare function formSupport(schema: JsonSchema | null): string | null;
6
+ export declare function configIsEditable(state: SessionPluginConfigState): boolean;
@@ -0,0 +1,40 @@
1
+ import type { PluginCatalogEntry, SessionPlugin, SessionPluginConfigSummary } from "@blade-hq/agent-client";
2
+ /**
3
+ * 连接器面板里的一行插件。
4
+ *
5
+ * 展示字段(名称、图标)和启用状态分开表达:目录接口在没有会话时也能给出名称与
6
+ * 图标,而「这次会话是否启用」只有会话接口知道。首页候选行恒为 `active: false`,
7
+ * 因为它只是待选,不代表已经激活。
8
+ */
9
+ export interface PluginConnectorItem {
10
+ name: string;
11
+ display_name: string | null;
12
+ /** 图标 token;null 时显示统一占位,不隐藏整行。 */
13
+ icon: string | null;
14
+ /** 图标从哪个接口取:账号级目录,还是会话内已准备的包。 */
15
+ iconSource: "account" | "session";
16
+ installed: boolean | null;
17
+ /** 会话里已提交的选择;首页候选恒为 false。 */
18
+ active: boolean;
19
+ status: string;
20
+ reason?: string | null;
21
+ config?: SessionPluginConfigSummary;
22
+ projected: boolean;
23
+ }
24
+ /** 首页候选:只有账号级目录,没有会话状态。 */
25
+ export declare function catalogToConnectorItems(catalog: PluginCatalogEntry[]): PluginConnectorItem[];
26
+ /**
27
+ * 会话列表叠加账号目录。
28
+ *
29
+ * 目录可用时展示字段以目录为准(包可能还没准备,会话列表拿不到名称和图标),
30
+ * 目录不可用时退回会话行自己的字段,这样已选插件仍然可以取消。
31
+ */
32
+ export declare function mergeConnectorItems(sessionPlugins: SessionPlugin[], catalog: PluginCatalogEntry[] | null): PluginConnectorItem[];
33
+ /**
34
+ * 一行的配置说明文案;权威状态来自配置接口。
35
+ *
36
+ * `unchecked` 刻意没有文案:列表没有读过用户的 Home,说任何话都是噪音,
37
+ * 入口是开关本身。
38
+ */
39
+ /** 按名称和显示名做本地过滤;空查询返回全部。 */
40
+ export declare function filterConnectorItems(items: PluginConnectorItem[], query: string): PluginConnectorItem[];
@@ -0,0 +1 @@
1
+ export declare const QueuePanelAdjacencyContext: import("react").Context<boolean | null>;
@@ -0,0 +1,40 @@
1
+ import type { BladeClient, SessionPluginActivation, SessionPluginConfigState } from "@blade-hq/agent-client";
2
+ import type { ConfiguringPlugin } from "./PluginConnectorList";
3
+ import { type PluginConnectorItem } from "./plugin-connector";
4
+ export interface UseSessionPluginActivationResult {
5
+ items: PluginConnectorItem[];
6
+ loading: boolean;
7
+ /** 插件列表本身读不到(Hub 不可用等),已有选择仍然可取消。 */
8
+ listError: boolean;
9
+ /** 某次启用/停用/准备失败了。 */
10
+ mutationError: boolean;
11
+ /** 正在为哪些插件提交意图;对应的开关在转圈,但仍然可点(点是取消)。 */
12
+ inFlight: Record<string, true>;
13
+ busy: boolean;
14
+ configuring: ConfiguringPlugin | null;
15
+ reload: () => void;
16
+ toggle: (item: PluginConnectorItem, next: boolean) => void;
17
+ retry: (item: PluginConnectorItem) => void;
18
+ editConfig: (item: PluginConnectorItem) => void;
19
+ onConfigSaved: (state: SessionPluginConfigState) => void;
20
+ onConfigClose: () => void;
21
+ }
22
+ /**
23
+ * 会话内插件启用的唯一实现。
24
+ *
25
+ * 顺序是「先准备配置,再提交 activation」:缺配置时开关不落到已启用、立刻弹表单,
26
+ * 保存成功才提交;取消、校验失败、配置读取失败都不提交。绝不先持久化 active=true
27
+ * 再靠补偿关掉——那样用户下次刷新会看到一个从没被成功打开的插件。
28
+ *
29
+ * 停用仍然直接提交:在服务端它只是取消一条数据库选择,不准备包、不连 MCP。但如果
30
+ * 这次「启用」只是还在准备、压根没提交过 activation,取消就只是放弃本地意图。
31
+ *
32
+ * 所有异步响应都按 (lifetime, mutation) 校验:迟到的准备或激活结果不会把已经取消 /
33
+ * 已经切走会话的插件重新打开;反过来,旧响应发现服务端落库顺序与用户最新意图不同时,
34
+ * 会重新提交最新意图。
35
+ */
36
+ export declare function useSessionPluginActivation({ client, sessionId, onChange, }: {
37
+ client: BladeClient;
38
+ sessionId: string;
39
+ onChange?: (plugin: SessionPluginActivation) => void;
40
+ }): UseSessionPluginActivationResult;
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;
@@ -18,9 +18,10 @@ export declare class BladeChatElement extends HTMLElement {
18
18
  connectedCallback(): void;
19
19
  /**
20
20
  * 自定义样式口子:<blade-chat> 的直接 <style> 子元素会被拷入 Shadow DOM,
21
- * 排在内置样式之后(同优先级时后者胜)。配合内置的 .blade-chat-* 类名
22
- * CSS 变量(--primary / --background 等,页面直接对 blade-chat 元素
23
- * 设置即可穿透),无需构建工具即可深度定制。
21
+ * 排在内置样式之后(同优先级时后者胜)。配合内置的 .blade-chat-* 类名、
22
+ * ::part()(每个可见区块都带与锚点同名的 part,如
23
+ * blade-chat::part(user-bubble))与 CSS 变量(--primary / --background 等,
24
+ * 页面直接对 blade-chat 元素设置即可穿透),无需构建工具即可深度定制。
24
25
  */
25
26
  private adoptUserStyles;
26
27
  disconnectedCallback(): void;
@@ -18,19 +18,47 @@ declare function getChat(element: Element | null): Promise<AgentSession>;
18
18
  declare const BladeAgent: {
19
19
  BladeClient: typeof agentClient.BladeClient;
20
20
  BladeApiError: typeof agentClient.BladeApiError;
21
+ isEntryGoneError: typeof agentClient.isEntryGoneError;
22
+ PollingBackoff: typeof agentClient.PollingBackoff;
23
+ EMPTY_PLATFORM_ENDPOINTS: agentClient.PlatformEndpoints;
24
+ loadPlatformEndpoints: typeof agentClient.loadPlatformEndpoints;
25
+ resolveServiceUrl: typeof agentClient.resolveServiceUrl;
21
26
  SDK_NAME: "agent-client";
22
27
  SDK_VERSION: string;
23
28
  AgentSession: typeof AgentSession;
24
29
  SessionHub: typeof agentClient.SessionHub;
30
+ isMcpAppData: typeof agentClient.isMcpAppData;
25
31
  SessionSetupError: typeof agentClient.SessionSetupError;
26
32
  createInitialSessionState: typeof agentClient.createInitialSessionState;
33
+ reconcileHistoricalUserTurns: typeof agentClient.reconcileHistoricalUserTurns;
27
34
  reconcileOptimisticUserTurns: typeof agentClient.reconcileOptimisticUserTurns;
28
35
  toReplaySnapshot: typeof agentClient.toReplaySnapshot;
36
+ EMPTY_SESSION_QUEUE: agentClient.SessionQueueSnapshot;
37
+ canCancelQueuedMessage: typeof agentClient.canCancelQueuedMessage;
38
+ canDeliverQueuedMessage: typeof agentClient.canDeliverQueuedMessage;
39
+ canEditQueuedMessage: typeof agentClient.canEditQueuedMessage;
40
+ isSessionQueueSnapshot: typeof agentClient.isSessionQueueSnapshot;
41
+ parseQueueAck: typeof agentClient.parseQueueAck;
42
+ queuePauseReasonLabel: typeof agentClient.queuePauseReasonLabel;
43
+ queuedMessageStatusLabel: typeof agentClient.queuedMessageStatusLabel;
44
+ shouldApplySnapshot: typeof agentClient.shouldApplySnapshot;
29
45
  connectEmbedded: typeof agentClient.connectEmbedded;
30
46
  isCommandEnvelope: typeof agentClient.isCommandEnvelope;
31
47
  isInboundEnvelope: typeof agentClient.isInboundEnvelope;
48
+ ComputersResource: typeof agentClient.ComputersResource;
49
+ canToggleComputer: typeof agentClient.canToggleComputer;
50
+ computerDaemonVersion: typeof agentClient.computerDaemonVersion;
51
+ computerOS: typeof agentClient.computerOS;
52
+ computerPlatformLabel: typeof agentClient.computerPlatformLabel;
53
+ computerState: typeof agentClient.computerState;
54
+ sortComputers: typeof agentClient.sortComputers;
32
55
  ModelsResource: typeof agentClient.ModelsResource;
56
+ ChatGroupsResource: typeof agentClient.ChatGroupsResource;
57
+ PluginsResource: typeof agentClient.PluginsResource;
58
+ hasChatRunEvent: typeof agentClient.hasChatRunEvent;
59
+ inferToolStatus: typeof agentClient.inferToolStatus;
33
60
  buildMessageContent: typeof agentClient.buildMessageContent;
61
+ chatErrorForDisplay: typeof agentClient.chatErrorForDisplay;
34
62
  contentPreview: typeof agentClient.contentPreview;
35
63
  extractTextAttachments: typeof agentClient.extractTextAttachments;
36
64
  getFileParts: typeof agentClient.getFileParts;
@@ -40,7 +68,20 @@ declare const BladeAgent: {
40
68
  isHiddenInternalMessage: typeof agentClient.isHiddenInternalMessage;
41
69
  normalizeMessageContent: typeof agentClient.normalizeMessageContent;
42
70
  transformSlashCommand: typeof agentClient.transformSlashCommand;
71
+ contextProjectionData: typeof agentClient.contextProjectionData;
72
+ getContextDisplayState: typeof agentClient.getContextDisplayState;
73
+ getContextGroupDisplayState: typeof agentClient.getContextGroupDisplayState;
74
+ groupAdjacentContextRuns: typeof agentClient.groupAdjacentContextRuns;
43
75
  latestPostChatFollowup: typeof agentClient.latestPostChatFollowup;
76
+ buildToolUiCardKey: typeof agentClient.buildToolUiCardKey;
77
+ collectInlineToolUiCards: typeof agentClient.collectInlineToolUiCards;
78
+ collectPreviewToolUiCards: typeof agentClient.collectPreviewToolUiCards;
79
+ isAppDevToolUiCard: typeof agentClient.isAppDevToolUiCard;
80
+ isInternalStatusToolUiCard: typeof agentClient.isInternalStatusToolUiCard;
81
+ isToolUiCard: typeof agentClient.isToolUiCard;
82
+ resolveToolUiCardContent: typeof agentClient.resolveToolUiCardContent;
83
+ prependOlder: typeof agentClient.prependOlder;
84
+ replaceWindow: typeof agentClient.replaceWindow;
44
85
  DEFAULT_REPLAY_SPEED: agentClient.ReplaySpeed;
45
86
  SessionInfo: import("arktype/internal/variants/object.ts").ObjectType<{
46
87
  id: string;
@@ -71,7 +112,11 @@ declare const BladeAgent: {
71
112
  disable_tools?: string[] | undefined;
72
113
  runtime_type?: string | null | undefined;
73
114
  daemon_id?: string | null | undefined;
115
+ agent_runtime_id?: string | null | undefined;
74
116
  workspace_path?: string | null | undefined;
117
+ ba_version?: string | null | undefined;
118
+ sandbox_version?: string | null | undefined;
119
+ chat_group_id?: string | null | undefined;
75
120
  match?: unknown;
76
121
  }, {}>;
77
122
  SessionStatus: import("arktype/internal/variants/string.ts").StringType<"completed" | "created" | "failed" | "interrupted" | "running" | "waiting_for_input", {}>;
@@ -87,7 +132,10 @@ declare const BladeAgent: {
87
132
  }, {}>;
88
133
  TaskStatus: import("arktype/internal/variants/string.ts").StringType<"done" | "failed" | "in_progress" | "pending" | "skipped", {}>;
89
134
  acceptedPostChatFollowupCompletesLatestRun: typeof agentClient.acceptedPostChatFollowupCompletesLatestRun;
135
+ acknowledgeTurnEvents: typeof agentClient.acknowledgeTurnEvents;
90
136
  ClientProjectionBuilder: typeof agentClient.ClientProjectionBuilder;
137
+ AuthBusyReconnect: typeof agentClient.AuthBusyReconnect;
138
+ authBusyRetryDelayMs: typeof agentClient.authBusyRetryDelayMs;
91
139
  createSocket: typeof agentClient.createSocket;
92
140
  getChat: typeof getChat;
93
141
  BladeChatElement: typeof BladeChatElement;
@@ -3,7 +3,8 @@ import {
3
3
  Ks,
4
4
  Qe,
5
5
  R
6
- } from "./chunk-ZXXLY4RM.js";
6
+ } from "./chunk-IA6J2NTB.js";
7
+ import "./chunk-G3PMV62Z.js";
7
8
 
8
9
  // ../../node_modules/.pnpm/streamdown@2.3.0_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/streamdown/dist/highlighted-body-B3W2YXNL.js
9
10
  import { useContext, useState, useEffect } from "react";
@@ -24,4 +25,4 @@ var L = ({ code: s, language: t, raw: e, className: n, ...d$1 }) => {
24
25
  export {
25
26
  L as HighlightedCodeBlockBody
26
27
  };
27
- //# sourceMappingURL=highlighted-body-B3W2YXNL-YD7FAP6V.js.map
28
+ //# sourceMappingURL=highlighted-body-B3W2YXNL-YF4GVJGP.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../node_modules/.pnpm/streamdown@2.3.0_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/streamdown/dist/highlighted-body-B3W2YXNL.js"],"sourcesContent":["\"use client\";\nimport {k,d,c}from'./chunk-RLXIAIE6.js';import {useContext,useState,useEffect}from'react';import {jsx}from'react/jsx-runtime';var L=({code:s,language:t,raw:e,className:n,...d$1})=>{let{shikiTheme:l}=useContext(k),o=d(),[m,i]=useState(e);return useEffect(()=>{if(!o){i(e);return}let g=o.highlight({code:s,language:t,themes:l},p=>{i(p);});g&&i(g);},[s,t,l,o,e]),jsx(c,{className:n,language:t,result:m,...d$1})};export{L as HighlightedCodeBlockBody};"],"mappings":";;;;;;;;AACwC,SAAQ,YAAW,UAAS,iBAAc;AAAQ,SAAQ,WAAQ;AAAoB,IAAI,IAAE,CAAC,EAAC,MAAK,GAAE,UAAS,GAAE,KAAI,GAAE,WAAU,GAAE,GAAG,IAAG,MAAI;AAAC,MAAG,EAAC,YAAW,EAAC,IAAE,WAAW,CAAC,GAAE,IAAE,GAAE,GAAE,CAAC,GAAE,CAAC,IAAE,SAAS,CAAC;AAAE,SAAO,UAAU,MAAI;AAAC,QAAG,CAAC,GAAE;AAAC,QAAE,CAAC;AAAE;AAAA,IAAM;AAAC,QAAI,IAAE,EAAE,UAAU,EAAC,MAAK,GAAE,UAAS,GAAE,QAAO,EAAC,GAAE,OAAG;AAAC,QAAE,CAAC;AAAA,IAAE,CAAC;AAAE,SAAG,EAAE,CAAC;AAAA,EAAE,GAAE,CAAC,GAAE,GAAE,GAAE,GAAE,CAAC,CAAC,GAAE,IAAI,IAAE,EAAC,WAAU,GAAE,UAAS,GAAE,QAAO,GAAE,GAAG,IAAG,CAAC;AAAC;","names":[]}
1
+ {"version":3,"sources":["../../../node_modules/.pnpm/streamdown@2.3.0_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/streamdown/dist/highlighted-body-B3W2YXNL.js"],"sourcesContent":["\"use client\";\nimport {k,d,c}from'./chunk-RLXIAIE6.js';import {useContext,useState,useEffect}from'react';import {jsx}from'react/jsx-runtime';var L=({code:s,language:t,raw:e,className:n,...d$1})=>{let{shikiTheme:l}=useContext(k),o=d(),[m,i]=useState(e);return useEffect(()=>{if(!o){i(e);return}let g=o.highlight({code:s,language:t,themes:l},p=>{i(p);});g&&i(g);},[s,t,l,o,e]),jsx(c,{className:n,language:t,result:m,...d$1})};export{L as HighlightedCodeBlockBody};"],"mappings":";;;;;;;;;AACwC,SAAQ,YAAW,UAAS,iBAAc;AAAQ,SAAQ,WAAQ;AAAoB,IAAI,IAAE,CAAC,EAAC,MAAK,GAAE,UAAS,GAAE,KAAI,GAAE,WAAU,GAAE,GAAG,IAAG,MAAI;AAAC,MAAG,EAAC,YAAW,EAAC,IAAE,WAAW,CAAC,GAAE,IAAE,GAAE,GAAE,CAAC,GAAE,CAAC,IAAE,SAAS,CAAC;AAAE,SAAO,UAAU,MAAI;AAAC,QAAG,CAAC,GAAE;AAAC,QAAE,CAAC;AAAE;AAAA,IAAM;AAAC,QAAI,IAAE,EAAE,UAAU,EAAC,MAAK,GAAE,UAAS,GAAE,QAAO,EAAC,GAAE,OAAG;AAAC,QAAE,CAAC;AAAA,IAAE,CAAC;AAAE,SAAG,EAAE,CAAC;AAAA,EAAE,GAAE,CAAC,GAAE,GAAE,GAAE,GAAE,CAAC,CAAC,GAAE,IAAI,IAAE,EAAC,WAAU,GAAE,UAAS,GAAE,QAAO,GAAE,GAAG,IAAG,CAAC;AAAC;","names":[]}
@@ -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。 */
@@ -0,0 +1,28 @@
1
+ export interface UseMessagePinOptions {
2
+ targetKey: string | null;
3
+ pinTarget: boolean;
4
+ /**
5
+ * 省略时按旧行为处理(视为一直流式中,只靠 targetKey 变化释放)——
6
+ * useMessagePin 是导出的公开 hook,加这个字段前如果直接改成必填,
7
+ * 所有已经在调用这个 hook 的外部使用方都会编译不过。
8
+ */
9
+ isStreaming?: boolean;
10
+ layoutKey?: string;
11
+ getScrollElement: () => HTMLElement | null;
12
+ getContentElement?: () => HTMLElement | null;
13
+ getTargetElement: () => HTMLElement | null;
14
+ getTargetScrollTop?: (scroll: HTMLElement) => number | null;
15
+ getSpacerHeight: () => number;
16
+ setSpacerHeight: (height: number) => void;
17
+ stopAutoScroll: () => void;
18
+ scrollToBottom: () => void;
19
+ margin?: number;
20
+ }
21
+ /**
22
+ * 用户发言顶置的共享状态机。SDK 和内置轻量列表只提供 DOM/虚拟列表适配器,
23
+ * 触发、调度、resize、手动接管和跟随交还的决策只在这里维护。
24
+ */
25
+ export declare function useMessagePin({ targetKey, pinTarget, isStreaming, layoutKey, getScrollElement, getContentElement, getTargetElement, getTargetScrollTop, getSpacerHeight, setSpacerHeight, stopAutoScroll, scrollToBottom, margin, }: UseMessagePinOptions): {
26
+ release: () => void;
27
+ isActive: () => boolean;
28
+ };