@springbrand/message-panel 0.2.0-alpha.56 → 0.3.0-alpha.1

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.
@@ -72,8 +72,6 @@ export interface CloudOsChatMessagesProps {
72
72
  /** 权威 Turn 生命周期;提供时替代本地 status 推断。 */
73
73
  turnActive?: boolean;
74
74
  isRecovering?: boolean;
75
- recoveryAttempt?: number;
76
- recoveryMax?: number;
77
75
  recoveryStatusLabel?: string;
78
76
  awaitingApproval?: boolean;
79
77
  /** 有 pending steer 时,活动占位说明「正在等当前步骤收尾」。 */
@@ -375,8 +373,6 @@ export function CloudOsChatMessages({
375
373
  status,
376
374
  turnActive,
377
375
  isRecovering = false,
378
- recoveryAttempt,
379
- recoveryMax,
380
376
  recoveryStatusLabel,
381
377
  awaitingApproval = false,
382
378
  hasPendingSteer = false,
@@ -550,8 +546,6 @@ export function CloudOsChatMessages({
550
546
  const activity = deriveTurnActivity(entries, {
551
547
  isActive,
552
548
  isRecovering,
553
- recoveryAttempt,
554
- recoveryMax,
555
549
  recoveryStatusLabel,
556
550
  awaitingApproval,
557
551
  hasPendingSteer,
@@ -722,8 +716,7 @@ export function CloudOsChatMessages({
722
716
  );
723
717
  const actionResultBlocks = entry.blocks.filter(
724
718
  (block): block is Extract<AssistantBlock, { kind: "actionPresentation" }> =>
725
- block.kind === "actionPresentation" &&
726
- !(block.presentation.state === "ready" && block.presentation.content.length === 0),
719
+ block.kind === "actionPresentation",
727
720
  );
728
721
  const finalMediaBlocks = entry.blocks.filter(
729
722
  (block): block is Extract<AssistantBlock, { kind: "image" | "file" }> =>
@@ -4,7 +4,7 @@ import {
4
4
  useSmooth,
5
5
  type SmoothOptions,
6
6
  } from "@assistant-ui/react";
7
- import { memo, useMemo, type ReactNode } from "react";
7
+ import { memo, useMemo, useRef, type ReactNode } from "react";
8
8
  import {
9
9
  defaultRehypePlugins,
10
10
  Streamdown,
@@ -135,8 +135,13 @@ function MarkdownMessageContent({
135
135
  resolveArtifactId?: CloudOsArtifactResolver;
136
136
  onOpenArtifact?: (artifactId: string) => void;
137
137
  }) {
138
- const part = useSmooth(useMessagePartText(), SMOOTH_STREAMING);
139
- const streaming = part.status.type === "running";
138
+ const received = useMessagePartText();
139
+ const initialText = useRef(received.text);
140
+ // A mounted snapshot is already visible history; only later deltas need a reveal.
141
+ const part = useSmooth(received.text === initialText.current
142
+ ? { ...received, status: { type: "complete" } }
143
+ : received, SMOOTH_STREAMING);
144
+ const streaming = received.status.type === "running" || part.status.type === "running";
140
145
  const rehypePlugins = useMemo(
141
146
  () =>
142
147
  resolveUrl
@@ -152,7 +152,7 @@ interface AskQuestion {
152
152
 
153
153
  function questionsOf(input: Record<string, unknown>): AskQuestion[] {
154
154
  if (!Array.isArray(input.questions)) return [];
155
- return input.questions.map((item) => {
155
+ return input.questions.flatMap((item) => {
156
156
  const question = (item ?? {}) as Record<string, unknown>;
157
157
  const options = Array.isArray(question.options)
158
158
  ? question.options.filter((option): option is string =>
@@ -164,14 +164,9 @@ function questionsOf(input: Record<string, unknown>): AskQuestion[] {
164
164
  question.responseType === "multi_select" ||
165
165
  question.responseType === "attachment"
166
166
  ? question.responseType
167
- : question.kind === "attachment"
168
- ? "attachment"
169
- : options.length === 0
170
- ? "text"
171
- : question.multiSelect === true
172
- ? "multi_select"
173
- : "single_select";
174
- return {
167
+ : undefined;
168
+ if (!responseType) return [];
169
+ return [{
175
170
  prompt: typeof question.question === "string"
176
171
  ? question.question
177
172
  : "Choose an option",
@@ -179,7 +174,7 @@ function questionsOf(input: Record<string, unknown>): AskQuestion[] {
179
174
  allowCustom: responseType === "text" || question.allowCustom === true,
180
175
  required: question.required === true,
181
176
  responseType,
182
- };
177
+ }];
183
178
  });
184
179
  }
185
180
 
@@ -973,8 +973,6 @@ export function deriveTurnActivity(
973
973
  options: {
974
974
  isActive: boolean;
975
975
  isRecovering?: boolean;
976
- recoveryAttempt?: number;
977
- recoveryMax?: number;
978
976
  recoveryStatusLabel?: string;
979
977
  awaitingApproval?: boolean;
980
978
  hasPendingSteer?: boolean;
@@ -983,10 +981,7 @@ export function deriveTurnActivity(
983
981
  if (options.isRecovering) {
984
982
  return {
985
983
  state: "connecting",
986
- label: options.recoveryStatusLabel ??
987
- (options.recoveryAttempt === undefined || options.recoveryMax === undefined
988
- ? "Recovering model response…"
989
- : `Recovering model response ${options.recoveryAttempt}/${options.recoveryMax}…`),
984
+ label: options.recoveryStatusLabel ?? "Recovering model response…",
990
985
  };
991
986
  }
992
987
  if (!options.isActive) return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@springbrand/message-panel",
3
- "version": "0.2.0-alpha.56",
3
+ "version": "0.3.0-alpha.1",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src",
@@ -0,0 +1 @@
1
+ {"version":"4.1.10","results":[[":bot/cycles.test.ts",{"duration":55.58770800000002,"failed":false}],[":bot/skins.test.ts",{"duration":3032.4465840000003,"failed":false}],[":bot/engine.test.ts",{"duration":100.501834,"failed":false}],[":bot/shape.test.ts",{"duration":16.04204200000001,"failed":false}],[":bot/expressions.test.ts",{"duration":8.212458999999996,"failed":false}],[":bot/face.test.ts",{"duration":3.6211250000000064,"failed":false}],[":drag.test.ts",{"duration":1.7712499999999807,"failed":false}],[":animation.test.ts",{"duration":2.3806249999999807,"failed":false}]]}
@@ -673,11 +673,7 @@ function askUserResponseType(question: Record<string, unknown>) {
673
673
  question.responseType === "multi_select" ||
674
674
  question.responseType === "attachment"
675
675
  ) return question.responseType;
676
- if (question.kind === "attachment") return "attachment";
677
- if (!Array.isArray(question.options) || question.options.length === 0) {
678
- return "text";
679
- }
680
- return question.multiSelect === true ? "multi_select" : "single_select";
676
+ return undefined;
681
677
  }
682
678
 
683
679
  function CamelAskUser({
@@ -840,17 +840,6 @@ export interface AskQuestion {
840
840
  required?: boolean;
841
841
  }
842
842
 
843
- function askQuestionResponseType(question: AskQuestion) {
844
- if (question.responseType) return question.responseType;
845
- const legacy = question as AskQuestion & {
846
- kind?: string;
847
- multiSelect?: boolean;
848
- };
849
- if (legacy.kind === "attachment") return "attachment";
850
- if (!question.options?.length) return "text";
851
- return legacy.multiSelect ? "multi_select" : "single_select";
852
- }
853
-
854
843
  interface AskAnswer {
855
844
  selections: string[];
856
845
  text: string;
@@ -878,7 +867,7 @@ export function AskUserPart({
878
867
  const resolvedSubmitted = submittedAnswers.length > 0;
879
868
  const valid = questions.length > 0 && questions.every(
880
869
  (question, index) => {
881
- const responseType = askQuestionResponseType(question);
870
+ const responseType = question.responseType;
882
871
  const answer = answerAt(index);
883
872
  if (
884
873
  answer.selections.length === 0 && !answer.text.trim()
@@ -898,7 +887,7 @@ export function AskUserPart({
898
887
  const answer = next[questionIndex]!;
899
888
  next[questionIndex] = {
900
889
  ...answer,
901
- selections: askQuestionResponseType(questions[questionIndex]!) ===
890
+ selections: questions[questionIndex]!.responseType ===
902
891
  "multi_select"
903
892
  ? answer.selections.includes(option)
904
893
  ? answer.selections.filter((item) => item !== option)
@@ -930,7 +919,7 @@ export function AskUserPart({
930
919
  data-state={resolvedSubmitted ? "submitted" : "pending"}
931
920
  >
932
921
  {questions.map((question, questionIndex) => {
933
- const responseType = askQuestionResponseType(question);
922
+ const responseType = question.responseType;
934
923
  const choice = responseType === "single_select" ||
935
924
  responseType === "multi_select";
936
925
  return (