@blade-hq/agent-react 2610.0.0-beta.29 → 2610.0.0-beta.30
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 +2 -0
- package/dist/components/AssistantTurnBlock.d.ts +5 -1
- package/dist/embed/entry.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +95 -7
- package/dist/index.js.map +1 -1
- package/dist/style.full.css +1 -1
- package/package.json +2 -2
- package/public-api.md +21 -1
package/README.md
CHANGED
|
@@ -158,6 +158,8 @@ await replay.exitToAutonomous() // 退出回放,之后真的运
|
|
|
158
158
|
|
|
159
159
|
`ChatView` 的普通展示模式不显示只供诊断的项目说明、可用能力和当前工作环境。需要自建诊断界面时,可直接使用独立的 `ContextCard`,属性见 `ContextCardProps`;状态到文案的映射来自 agent-client 的 `getContextDisplayState`,不需要接入方重复判断。底层数据类型为 `ContextProjectionData` / `ContextProjectionFields`,展示结果为 `ContextDisplayState`,并保留 `ContextAction`、`ContextSourceInfo` 和 `contextProjectionData` 给 headless 消费方。
|
|
160
160
|
|
|
161
|
+
记忆引用提示可通过 `MemoryRefsHint` 展示,`collectMemoryRefs` 用于从一轮消息中聚合引用,保证宿主自定义消息布局与 SDK 默认界面保持一致。
|
|
162
|
+
|
|
161
163
|
`onFollowupInteraction` 使用 `FollowupInteractionEvent`,覆盖下一步建议展示/采纳、成果展示/打开/下载以及结果评分。SDK 不内置 PostHog 等分析厂商;宿主回调抛错也不会中断用户点击或下载。
|
|
162
164
|
文件成果以文件名为文本的标准下载链接展示;Vue / 纯 HTML 使用的 `<blade-chat>` 与 `ChatView` 行为一致。
|
|
163
165
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AskUserAnswerData, ChatMessage } from "@blade-hq/agent-client";
|
|
1
|
+
import type { AskUserAnswerData, ChatMessage, MemoryRefInfo } from "@blade-hq/agent-client";
|
|
2
2
|
import { type ToolCallRenderer } from "./ToolCallBlock";
|
|
3
3
|
interface Props {
|
|
4
4
|
messages: ChatMessage[];
|
|
@@ -23,4 +23,8 @@ export declare function getExecutionDurationMs({ messages, isStreaming, now, }:
|
|
|
23
23
|
}): number;
|
|
24
24
|
/** 一轮助手回复:执行过程默认折叠,最终正文始终显示在摘要下方。 */
|
|
25
25
|
export declare function AssistantTurnBlock({ messages, isStreaming, askAnswers, onAnswer, sessionStatus, toolCallRenderer, sessionId, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
export declare function collectMemoryRefs(messages: ChatMessage[]): MemoryRefInfo[];
|
|
27
|
+
export declare function MemoryRefsHint({ refs }: {
|
|
28
|
+
refs: MemoryRefInfo[];
|
|
29
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
26
30
|
export {};
|
package/dist/embed/entry.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ declare const BladeAgent: {
|
|
|
38
38
|
sortComputers: typeof agentClient.sortComputers;
|
|
39
39
|
ModelsResource: typeof agentClient.ModelsResource;
|
|
40
40
|
buildMessageContent: typeof agentClient.buildMessageContent;
|
|
41
|
+
chatErrorForDisplay: typeof agentClient.chatErrorForDisplay;
|
|
41
42
|
contentPreview: typeof agentClient.contentPreview;
|
|
42
43
|
extractTextAttachments: typeof agentClient.extractTextAttachments;
|
|
43
44
|
getFileParts: typeof agentClient.getFileParts;
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export type { ReplayMismatchPromptProps } from "./components/ReplayMismatchPromp
|
|
|
24
24
|
export type { ToolCallRenderer } from "./components/ToolCallBlock";
|
|
25
25
|
export { ContextCard } from "./components/ContextCard";
|
|
26
26
|
export type { ContextCardProps } from "./components/ContextCard";
|
|
27
|
+
export { collectMemoryRefs, MemoryRefsHint } from "./components/AssistantTurnBlock";
|
|
27
28
|
export { isAgentComputerCommand, isAgentComputerToolCall, classifyAgentComputerLaunchOutcome, } from "./lib/agent-computer-command";
|
|
28
29
|
export type { AgentComputerLaunchOutcome } from "./lib/agent-computer-command";
|
|
29
30
|
export * from "@blade-hq/agent-client";
|
package/dist/index.js
CHANGED
|
@@ -1221,6 +1221,9 @@ function ReplayMismatchPrompt({ mismatch, className }) {
|
|
|
1221
1221
|
);
|
|
1222
1222
|
}
|
|
1223
1223
|
|
|
1224
|
+
// src/components/ChatSurface.tsx
|
|
1225
|
+
import { chatErrorForDisplay as chatErrorForDisplay2 } from "@blade-hq/agent-client";
|
|
1226
|
+
|
|
1224
1227
|
// src/components/ChatInput.tsx
|
|
1225
1228
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1226
1229
|
function isImeCompositionKey(event) {
|
|
@@ -2708,6 +2711,32 @@ function getLastContentMessage(messages) {
|
|
|
2708
2711
|
}
|
|
2709
2712
|
return null;
|
|
2710
2713
|
}
|
|
2714
|
+
function getOrderedMessageParts(message, toolCalls) {
|
|
2715
|
+
const blocks = message.blocks ?? [];
|
|
2716
|
+
if (!blocks.some((block) => block.type === "text") || !blocks.some((block) => block.type === "tool_use")) return [];
|
|
2717
|
+
const toolsById = new Map(toolCalls.map((toolCall) => [toolCall.id, toolCall]));
|
|
2718
|
+
const seenToolIds = /* @__PURE__ */ new Set();
|
|
2719
|
+
const parts = [];
|
|
2720
|
+
for (const [index, block] of blocks.entries()) {
|
|
2721
|
+
if (block.type === "text" && block.content != null && block.content !== "") {
|
|
2722
|
+
const content = Array.isArray(block.content) ? block.content : String(block.content);
|
|
2723
|
+
parts.push({ type: "text", key: `text-${index}`, content });
|
|
2724
|
+
}
|
|
2725
|
+
if (block.type !== "tool_use" || !block.tool_call_id) continue;
|
|
2726
|
+
const toolCall = toolsById.get(block.tool_call_id);
|
|
2727
|
+
if (!toolCall) continue;
|
|
2728
|
+
seenToolIds.add(toolCall.id);
|
|
2729
|
+
const previous = parts[parts.length - 1];
|
|
2730
|
+
if (previous?.type === "tools") previous.toolCalls.push(toolCall);
|
|
2731
|
+
else parts.push({ type: "tools", key: `tools-${index}`, toolCalls: [toolCall] });
|
|
2732
|
+
}
|
|
2733
|
+
const missingTools = toolCalls.filter((toolCall) => !seenToolIds.has(toolCall.id));
|
|
2734
|
+
if (seenToolIds.size === 0) return [];
|
|
2735
|
+
if (missingTools.length > 0) {
|
|
2736
|
+
parts.push({ type: "tools", key: "tools-missing", toolCalls: missingTools });
|
|
2737
|
+
}
|
|
2738
|
+
return parts;
|
|
2739
|
+
}
|
|
2711
2740
|
function findLatestReasoningMessageIndex(messages) {
|
|
2712
2741
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
2713
2742
|
if (messages[index].reasoning) return index;
|
|
@@ -2883,6 +2912,13 @@ function AssistantTurnBlock({
|
|
|
2883
2912
|
(message) => message.status === "failed" && !hasRenderableMessageContent(message)
|
|
2884
2913
|
);
|
|
2885
2914
|
const finalMessage = getLastContentMessage(messages);
|
|
2915
|
+
const turnToolCalls = messages.flatMap((message) => message.tool_calls ?? []);
|
|
2916
|
+
const finalOrderedParts = finalMessage ? getOrderedMessageParts(
|
|
2917
|
+
finalMessage,
|
|
2918
|
+
(finalMessage.tool_calls ?? []).filter(
|
|
2919
|
+
(toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion"
|
|
2920
|
+
)
|
|
2921
|
+
) : [];
|
|
2886
2922
|
const hasExecutionProcess = messages.some(
|
|
2887
2923
|
(message) => message.reasoning || (message.tool_calls?.length ?? 0) > 0
|
|
2888
2924
|
);
|
|
@@ -2921,6 +2957,7 @@ function AssistantTurnBlock({
|
|
|
2921
2957
|
return () => window.clearInterval(timer);
|
|
2922
2958
|
}, [hasLiveStartTime, isStreaming]);
|
|
2923
2959
|
const liveExecutionDurationMs = isStreaming ? getExecutionDurationMs({ messages, isStreaming, now: clock }) : executionDurationMs;
|
|
2960
|
+
const memoryRefs = collectMemoryRefs(messages);
|
|
2924
2961
|
if (!hasExecutionProcess) {
|
|
2925
2962
|
return /* @__PURE__ */ jsxs9(
|
|
2926
2963
|
"div",
|
|
@@ -2928,6 +2965,7 @@ function AssistantTurnBlock({
|
|
|
2928
2965
|
"aria-busy": isStreaming || void 0,
|
|
2929
2966
|
className: "blade-chat-assistant-turn flex flex-col gap-3",
|
|
2930
2967
|
children: [
|
|
2968
|
+
memoryRefs.length > 0 ? /* @__PURE__ */ jsx11(MemoryRefsHint, { refs: memoryRefs }) : null,
|
|
2931
2969
|
hasInterrupted && /* @__PURE__ */ jsx11("div", { className: "ml-4 w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }),
|
|
2932
2970
|
hasFailedWithoutContent && /* @__PURE__ */ jsx11("div", { className: "ml-4 w-fit rounded-full border border-red-500/30 bg-red-500/10 px-2.5 py-1 text-[10px] font-medium text-red-400", children: "\u751F\u6210\u5931\u8D25" }),
|
|
2933
2971
|
messages.map((message, index) => {
|
|
@@ -2957,6 +2995,7 @@ function AssistantTurnBlock({
|
|
|
2957
2995
|
"aria-busy": isStreaming || void 0,
|
|
2958
2996
|
className: "blade-chat-assistant-turn flex flex-col gap-3",
|
|
2959
2997
|
children: [
|
|
2998
|
+
memoryRefs.length > 0 ? /* @__PURE__ */ jsx11(MemoryRefsHint, { refs: memoryRefs }) : null,
|
|
2960
2999
|
hasInterrupted && /* @__PURE__ */ jsx11("div", { className: "ml-4 w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }),
|
|
2961
3000
|
hasFailedWithoutContent && /* @__PURE__ */ jsx11("div", { className: "ml-4 w-fit rounded-full border border-red-500/30 bg-red-500/10 px-2.5 py-1 text-[10px] font-medium text-red-400", children: "\u751F\u6210\u5931\u8D25" }),
|
|
2962
3001
|
/* @__PURE__ */ jsxs9("div", { className: "flex w-full items-start gap-2.5", children: [
|
|
@@ -3013,6 +3052,7 @@ function AssistantTurnBlock({
|
|
|
3013
3052
|
const toolCalls = (message.tool_calls ?? []).filter(
|
|
3014
3053
|
(toolCall) => formatToolName(toolCall.name) !== "AskUserQuestion"
|
|
3015
3054
|
);
|
|
3055
|
+
const orderedParts = getOrderedMessageParts(message, toolCalls);
|
|
3016
3056
|
const showReasoning = !!message.reasoning && isStreaming && index === latestReasoningIndex;
|
|
3017
3057
|
return /* @__PURE__ */ jsxs9(
|
|
3018
3058
|
"div",
|
|
@@ -3020,7 +3060,21 @@ function AssistantTurnBlock({
|
|
|
3020
3060
|
className: "flex flex-col gap-3",
|
|
3021
3061
|
children: [
|
|
3022
3062
|
showReasoning && message.reasoning ? /* @__PURE__ */ jsx11(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }) : null,
|
|
3023
|
-
|
|
3063
|
+
orderedParts.length > 0 ? orderedParts.map(
|
|
3064
|
+
(part) => part.type === "text" ? /* @__PURE__ */ jsx11(
|
|
3065
|
+
AssistantMessageContent,
|
|
3066
|
+
{
|
|
3067
|
+
message: { ...message, content: part.content, tool_calls: turnToolCalls },
|
|
3068
|
+
sessionId,
|
|
3069
|
+
streaming: streamingThis,
|
|
3070
|
+
compact: true
|
|
3071
|
+
},
|
|
3072
|
+
part.key
|
|
3073
|
+
) : /* @__PURE__ */ jsx11("div", { className: "flex flex-col gap-0.5", children: part.toolCalls.map((toolCall) => {
|
|
3074
|
+
const custom = toolCallRenderer?.(toolCall);
|
|
3075
|
+
return custom !== null && custom !== void 0 ? /* @__PURE__ */ jsx11("div", { children: custom }, toolCall.id) : formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */ jsx11(AgentLoopBlock, { toolCall }, toolCall.id) : /* @__PURE__ */ jsx11(ExecutionToolRow, { toolCall }, toolCall.id);
|
|
3076
|
+
}) }, part.key)
|
|
3077
|
+
) : hasRenderableMessageContent(message) && message !== finalMessage ? /* @__PURE__ */ jsx11(
|
|
3024
3078
|
AssistantMessageContent,
|
|
3025
3079
|
{
|
|
3026
3080
|
message,
|
|
@@ -3029,7 +3083,7 @@ function AssistantTurnBlock({
|
|
|
3029
3083
|
compact: true
|
|
3030
3084
|
}
|
|
3031
3085
|
) : null,
|
|
3032
|
-
toolCalls.length > 0 ? /* @__PURE__ */ jsx11("div", { className: "flex flex-col gap-0.5", children: toolCalls.map((toolCall) => {
|
|
3086
|
+
orderedParts.length === 0 && toolCalls.length > 0 ? /* @__PURE__ */ jsx11("div", { className: "flex flex-col gap-0.5", children: toolCalls.map((toolCall) => {
|
|
3033
3087
|
const custom = toolCallRenderer?.(toolCall);
|
|
3034
3088
|
return custom !== null && custom !== void 0 ? /* @__PURE__ */ jsx11("div", { children: custom }, toolCall.id) : formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */ jsx11(AgentLoopBlock, { toolCall }, toolCall.id) : /* @__PURE__ */ jsx11(ExecutionToolRow, { toolCall }, toolCall.id);
|
|
3035
3089
|
}) }) : null
|
|
@@ -3038,7 +3092,7 @@ function AssistantTurnBlock({
|
|
|
3038
3092
|
message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
|
|
3039
3093
|
);
|
|
3040
3094
|
}) }) : null,
|
|
3041
|
-
finalMessage ? /* @__PURE__ */ jsx11("div", { className: "ml-10", children: /* @__PURE__ */ jsx11(
|
|
3095
|
+
finalMessage && (effectiveMode === "compact" || finalOrderedParts.length === 0) ? /* @__PURE__ */ jsx11("div", { className: "ml-10", children: /* @__PURE__ */ jsx11(
|
|
3042
3096
|
AssistantMessageContent,
|
|
3043
3097
|
{
|
|
3044
3098
|
message: finalMessage,
|
|
@@ -3063,6 +3117,33 @@ function AssistantTurnBlock({
|
|
|
3063
3117
|
}
|
|
3064
3118
|
);
|
|
3065
3119
|
}
|
|
3120
|
+
function collectMemoryRefs(messages) {
|
|
3121
|
+
const refs = /* @__PURE__ */ new Map();
|
|
3122
|
+
for (const message of messages) {
|
|
3123
|
+
for (const ref of message.memory_refs ?? []) if (!refs.has(ref.id)) refs.set(ref.id, ref);
|
|
3124
|
+
}
|
|
3125
|
+
return [...refs.values()];
|
|
3126
|
+
}
|
|
3127
|
+
function MemoryRefsHint({ refs }) {
|
|
3128
|
+
const [expanded, setExpanded] = useState10(false);
|
|
3129
|
+
const label = refs.some((ref) => ref.skill_name) ? "\u53C2\u8003\u4E86\u8BE5\u6280\u80FD\u7684\u5386\u53F2\u7ECF\u9A8C" : "\u53C2\u8003\u4E86\u5386\u53F2\u7ECF\u9A8C";
|
|
3130
|
+
return /* @__PURE__ */ jsxs9("div", { className: "blade-chat-memory-refs ml-1 w-full max-w-[680px]", children: [
|
|
3131
|
+
/* @__PURE__ */ jsxs9("button", { type: "button", onClick: () => setExpanded((value) => !value), className: "inline-flex h-8 items-center gap-1.5 rounded-lg border border-[hsl(var(--primary)/0.22)] bg-[hsl(var(--primary)/0.07)] px-3 text-xs font-medium text-[hsl(var(--primary))]", children: [
|
|
3132
|
+
/* @__PURE__ */ jsx11(BookOpen, { size: 12 }),
|
|
3133
|
+
/* @__PURE__ */ jsxs9("span", { children: [
|
|
3134
|
+
label,
|
|
3135
|
+
"\uFF08",
|
|
3136
|
+
refs.length,
|
|
3137
|
+
"\uFF09"
|
|
3138
|
+
] }),
|
|
3139
|
+
/* @__PURE__ */ jsx11(ChevronRight, { size: 10, className: cn("transition-transform", expanded && "rotate-90") })
|
|
3140
|
+
] }),
|
|
3141
|
+
expanded ? /* @__PURE__ */ jsx11("div", { className: "mt-2 flex flex-col gap-2 rounded-xl border border-[hsl(var(--border)/0.8)] bg-[hsl(var(--muted)/0.28)] p-2.5", children: refs.map((ref) => /* @__PURE__ */ jsxs9("div", { className: "rounded-lg border border-[hsl(var(--border)/0.55)] bg-[hsl(var(--background)/0.72)] px-3 py-2.5 text-xs", children: [
|
|
3142
|
+
/* @__PURE__ */ jsx11("p", { className: "line-clamp-2 break-words leading-5", children: ref.content_preview }),
|
|
3143
|
+
ref.skill_name ? /* @__PURE__ */ jsx11("span", { className: "mt-1 inline-flex text-[10px] text-[hsl(var(--primary))]", children: ref.skill_name }) : null
|
|
3144
|
+
] }, ref.id)) }) : null
|
|
3145
|
+
] });
|
|
3146
|
+
}
|
|
3066
3147
|
function AssistantMessageContent({
|
|
3067
3148
|
message,
|
|
3068
3149
|
sessionId,
|
|
@@ -3565,7 +3646,12 @@ function PostChatFollowupBlock({
|
|
|
3565
3646
|
}
|
|
3566
3647
|
|
|
3567
3648
|
// src/components/UserMessageBubble.tsx
|
|
3568
|
-
import {
|
|
3649
|
+
import {
|
|
3650
|
+
chatErrorForDisplay,
|
|
3651
|
+
getFileParts as getFileParts2,
|
|
3652
|
+
getImageParts as getImageParts2,
|
|
3653
|
+
getTextContent as getTextContent2
|
|
3654
|
+
} from "@blade-hq/agent-client";
|
|
3569
3655
|
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3570
3656
|
function isUserMessage(message) {
|
|
3571
3657
|
return message.role === "user";
|
|
@@ -3610,8 +3696,8 @@ function ErrorMessageBlock({
|
|
|
3610
3696
|
message,
|
|
3611
3697
|
className
|
|
3612
3698
|
}) {
|
|
3613
|
-
const text = getTextContent2(message.content);
|
|
3614
|
-
return /* @__PURE__ */ jsx14("div", { className: cn("blade-chat-error-row flex justify-
|
|
3699
|
+
const text = chatErrorForDisplay(getTextContent2(message.content));
|
|
3700
|
+
return /* @__PURE__ */ jsx14("div", { className: cn("blade-chat-error-row flex min-w-0 justify-start", className), children: /* @__PURE__ */ jsx14("div", { className: "blade-chat-error-block min-w-0 max-w-full whitespace-pre-wrap break-words border-l-[3px] border-[hsl(var(--border))] px-3 py-1 text-left text-sm leading-7 text-[hsl(var(--muted-foreground))] [overflow-wrap:anywhere]", children: text }) });
|
|
3615
3701
|
}
|
|
3616
3702
|
|
|
3617
3703
|
// src/components/MessageList.tsx
|
|
@@ -3987,7 +4073,7 @@ function ChatSurface({
|
|
|
3987
4073
|
banner,
|
|
3988
4074
|
errorMessage && /* @__PURE__ */ jsxs14("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
|
|
3989
4075
|
/* @__PURE__ */ jsx16(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
|
|
3990
|
-
/* @__PURE__ */ jsx16("span", { children: errorMessage })
|
|
4076
|
+
/* @__PURE__ */ jsx16("span", { className: "min-w-0 whitespace-pre-wrap break-words [overflow-wrap:anywhere]", children: chatErrorForDisplay2(errorMessage) })
|
|
3991
4077
|
] }),
|
|
3992
4078
|
slots?.header,
|
|
3993
4079
|
/* @__PURE__ */ jsx16(
|
|
@@ -4557,9 +4643,11 @@ export {
|
|
|
4557
4643
|
ContextCard,
|
|
4558
4644
|
LlmChat,
|
|
4559
4645
|
MarkdownContent,
|
|
4646
|
+
MemoryRefsHint,
|
|
4560
4647
|
ReplayBar,
|
|
4561
4648
|
ReplayMismatchPrompt,
|
|
4562
4649
|
classifyAgentComputerLaunchOutcome,
|
|
4650
|
+
collectMemoryRefs,
|
|
4563
4651
|
isAgentComputerCommand,
|
|
4564
4652
|
isAgentComputerToolCall,
|
|
4565
4653
|
useAgentSession,
|