@baishuyun/chat-sdk 0.0.17 → 0.0.18

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 (61) hide show
  1. package/.turbo/turbo-build.log +178 -115
  2. package/CHANGELOG.md +8 -0
  3. package/dist/chat-sdk.js +26425 -34262
  4. package/dist/chat-sdk.js.map +1 -1
  5. package/dist/chat-sdk.umd.cjs +219 -296
  6. package/dist/chat-sdk.umd.cjs.map +1 -1
  7. package/dist/index.css +1 -1
  8. package/package.json +4 -4
  9. package/src/chat.tsx +4 -1
  10. package/src/components/biz-comp/chat-client.tsx +1 -1
  11. package/src/components/biz-comp/multi-modal-input/index.tsx +22 -5
  12. package/src/components/biz-comp/preview-message.tsx +25 -3
  13. package/src/components/bs-ui/attachment-part-group.tsx +5 -2
  14. package/src/components/bs-ui/attachment-part.tsx +14 -9
  15. package/src/components/bs-ui/attachments-previewer.tsx +2 -2
  16. package/src/components/bs-ui/base-button.tsx +14 -4
  17. package/src/components/bs-ui/border-animation.tsx +107 -0
  18. package/src/components/bs-ui/bs-icons.tsx +6 -0
  19. package/src/components/bs-ui/confirm-dialog.tsx +17 -11
  20. package/src/components/bs-ui/fields-previewer.tsx +16 -8
  21. package/src/components/bs-ui/img-part.tsx +4 -2
  22. package/src/components/bs-ui/previewer-header.tsx +26 -7
  23. package/src/components/bs-ui/primary-entry-btn.tsx +2 -1
  24. package/src/index.tsx +0 -1
  25. package/src/lib/utils.ts +60 -2
  26. package/src/plugins/form-builder-plugin/components/create-form-confirm.tsx +0 -2
  27. package/src/plugins/form-builder-plugin/components/design-doc-part.tsx +19 -0
  28. package/src/plugins/form-builder-plugin/components/fields-part.tsx +78 -0
  29. package/src/plugins/form-builder-plugin/components/msg-part.tsx +20 -165
  30. package/src/plugins/form-builder-plugin/components/suggestion-part.tsx +62 -0
  31. package/src/plugins/form-builder-plugin/hooks/index.tsx +50 -0
  32. package/src/plugins/form-builder-plugin/index.ts +39 -30
  33. package/src/plugins/form-builder-plugin/types.ts +19 -2
  34. package/src/plugins/form-builder-plugin/utils/get-render-strategy.ts +27 -0
  35. package/src/plugins/form-builder-plugin/utils/index.ts +44 -37
  36. package/src/plugins/form-filling-plugin/components/FormFillingOpeningLines.tsx +4 -0
  37. package/src/plugins/form-filling-plugin/components/batch-fill-part.tsx +17 -0
  38. package/src/plugins/form-filling-plugin/components/batch-generator-action.tsx +6 -1
  39. package/src/plugins/form-filling-plugin/components/entry-btn.tsx +1 -1
  40. package/src/plugins/form-filling-plugin/components/first-batch-generating-animation.tsx +6 -16
  41. package/src/plugins/form-filling-plugin/components/msg-part.tsx +39 -122
  42. package/src/plugins/form-filling-plugin/components/non-first-batch-generating-animation.tsx +9 -19
  43. package/src/plugins/form-filling-plugin/components/single-fill-part.tsx +42 -0
  44. package/src/plugins/form-filling-plugin/hooks/use-conversation-id-in-ctx.ts +13 -0
  45. package/src/plugins/form-filling-plugin/hooks/use-fields-data.ts +110 -0
  46. package/src/plugins/form-filling-plugin/index.ts +49 -43
  47. package/src/plugins/form-filling-plugin/types.ts +19 -1
  48. package/src/plugins/report-query-plugin/components/query-msg-part.tsx +13 -4
  49. package/src/plugins/report-query-plugin/index.ts +20 -11
  50. package/src/store/index.ts +0 -1
  51. package/src/stories/BorderAnimation.stories.tsx +116 -0
  52. package/src/stories/PreviewerHeader.stories.tsx +24 -0
  53. package/src/style.css +25 -0
  54. package/src/plugins/form-builder-plugin/hooks/index.ts +0 -0
  55. package/src/plugins/general-model-form-builder-plugin/components/confirmer.tsx +0 -90
  56. package/src/plugins/general-model-form-builder-plugin/components/ghost-evt-dispatcher.tsx +0 -69
  57. package/src/plugins/general-model-form-builder-plugin/components/msg-part.tsx +0 -147
  58. package/src/plugins/general-model-form-builder-plugin/components/new-confirmer.tsx +0 -191
  59. package/src/plugins/general-model-form-builder-plugin/const.ts +0 -3
  60. package/src/plugins/general-model-form-builder-plugin/index.ts +0 -20
  61. package/src/plugins/general-model-form-builder-plugin/types.ts +0 -1
@@ -1,178 +1,33 @@
1
1
  import { MarkdownMsgpart } from '@/components/biz-comp/markdown-part';
2
- import { MessageContent } from '@/components/biz-comp/message-content';
3
- import { FollowUp } from './follow-up';
4
2
 
5
- import {
6
- GetFieldJsonInfo,
7
- getIconValue,
8
- IsFieldsJsonPart,
9
- IsSuggesstionPart,
10
- NeedToAppendFieldsSaveConfirm,
11
- } from '@/lib/utils';
12
- import { MsgPartCompProps, RealFormInfo } from '@baishuyun/types';
3
+ import { MsgPartCompProps } from '@baishuyun/types';
13
4
  import { TextUIPart } from 'ai';
14
5
  import { useFieldsConfirmed } from '../hooks/use-fields-confirmed';
15
- import { useEvtBus } from '@/hooks/use-evt-bus';
16
- import { usePlugin } from '@/hooks/use-plugin';
17
- import { MCP_PLUGIN_NAME } from '../const';
18
- import { FormBuilderPlugin } from '..';
19
- import { CreateFormConfirm } from './create-form-confirm';
20
- import { FakeBotMessage } from '@/components/biz-comp/FakeBotMsg';
21
- import {
22
- FieldCheckerListMsg,
23
- FieldCheckerListMsgRef,
24
- } from '@/components/biz-comp/FieldCheckerListMsg';
25
- import { PrimaryConfirmBtn } from '@/components/bs-ui/primary-confirm-btn';
26
- import { FieldIcon } from '../../../components/biz-comp/field-icon';
27
- import { CheckerIcon } from '@/components/bs-ui/bs-icons';
28
- import { usePluginCtx } from '@/hooks/use-plugin-ctx';
29
- import { McpFormBuilderPluginCtx } from '../types';
30
- import { DesignInfo } from './design-info';
31
- import { useRef } from 'react';
6
+ import { FormBuildPartRenderStrategyMap } from '../types';
7
+ import { FieldsPart } from './fields-part';
8
+ import { SuggestionPart, SuggestionPrefixPart } from './suggestion-part';
9
+ import { getRenderStrategy } from '../utils/get-render-strategy';
10
+ import { DesignDocPart } from './design-doc-part';
11
+
12
+ const FormBuildPartRenderer: FormBuildPartRenderStrategyMap = {
13
+ fields: FieldsPart,
14
+ followup: SuggestionPart,
15
+ followup_prefix: SuggestionPrefixPart,
16
+ design_doc: DesignDocPart,
17
+ markdown: MarkdownMsgpart,
18
+ unknown: MarkdownMsgpart,
19
+ };
32
20
 
33
21
  export const McpMessagePart = (props: MsgPartCompProps) => {
34
- const { part: p, sendMessage, status } = props;
35
-
36
- const fieldsConfirmed = useFieldsConfirmed();
22
+ const { part: p } = props;
37
23
 
38
24
  const part = p as TextUIPart;
39
25
 
40
- const isFieldsJson = IsFieldsJsonPart(part);
41
-
42
- const isFieldsSaveConfirm = NeedToAppendFieldsSaveConfirm(part);
43
-
44
- const evtBus = useEvtBus();
45
-
46
- const plugin = usePlugin<FormBuilderPlugin>(MCP_PLUGIN_NAME);
47
-
48
- const checkerRef = useRef<FieldCheckerListMsgRef>(null);
49
-
50
- const ctx = usePluginCtx<McpFormBuilderPluginCtx, FormBuilderPlugin>(MCP_PLUGIN_NAME);
51
-
52
- const fieldsParts = Array.isArray(part) && part.length ? part : isFieldsJson ? [part] : [];
26
+ const strategy = getRenderStrategy(part);
53
27
 
54
- if (fieldsParts.length) {
55
- const fieldPropsArray = fieldsParts.map((p) => {
56
- const field = GetFieldJsonInfo(p);
57
- return {
58
- field,
59
- disabled: fieldsConfirmed,
60
- onLoaded: (field: any) => {
61
- const finalField = plugin?.onBeforeFieldCreate(field);
62
- evtBus.emit('form-builder-FieldCreated', {
63
- field: finalField,
64
- checked: true,
65
- });
66
- plugin?.onAfterFieldCreate(field);
67
- },
68
- icon: <FieldIcon type={field.widget?.type} />,
69
- onChange: (check: boolean, field: any, parentFieldName?: string, index?: number) => {
70
- console.log('field checked changed:', { check, field, parentFieldName, index });
71
- evtBus.emit('form-builder-FieldCheckedChanged', {
72
- field,
73
- checked: check,
74
- parentFieldName,
75
- index,
76
- });
77
- },
78
- };
79
- });
28
+ const PartComp = FormBuildPartRenderer[strategy] || MarkdownMsgpart;
80
29
 
81
- const formName = plugin?.getCurrentWorkingForm()?.formName || '';
82
-
83
- return (
84
- <MessageContent className="gap-0 py-0" compact>
85
- <div>
86
- <b style={{ display: 'inline-block' }}>{formName}</b>
87
- {` 已生成${fieldPropsArray.length}个字段`}
88
- </div>
89
- <FieldCheckerListMsg
90
- ref={checkerRef}
91
- fields={fieldPropsArray}
92
- streaming={status === 'streaming'}
93
- confirmed={fieldsConfirmed}
94
- >
95
- {status === 'ready' ? (
96
- <PrimaryConfirmBtn
97
- className="mt-[20px] mb-[10px]"
98
- disabledWithInfo={fieldsConfirmed}
99
- onClick={() => {
100
- evtBus.emit(
101
- 'form-builder-FieldsConfirmed',
102
- plugin?.getCurrentWorkingForm() as RealFormInfo
103
- );
104
- plugin.onAfterFieldsSave((processedInfo) => {
105
- evtBus.emit('form-builder-FieldsConfirmed', processedInfo as RealFormInfo);
106
- });
107
- }}
108
- >
109
- {fieldsConfirmed ? (
110
- <>
111
- <CheckerIcon className="text-[#0265ff]" /> 已保存{' '}
112
- {checkerRef.current?.getCheckedFieldsLength() ?? 0} 个字段
113
- </>
114
- ) : (
115
- '保存字段'
116
- )}
117
- </PrimaryConfirmBtn>
118
- ) : null}
119
- </FieldCheckerListMsg>
120
- {status === 'ready'
121
- ? '请选择需要的字段添加到表单。您可以补充描述后重新生成,表单中已添加字段在下次生成时保留。'
122
- : null}
123
- </MessageContent>
124
- );
125
- }
126
-
127
- // suggestion
128
- if (IsSuggesstionPart(part)) {
129
- return fieldsConfirmed ? (
130
- <FollowUp
131
- title={part.text}
132
- description={part.text}
133
- onSelect={(title, icon) => {
134
- if (ctx) {
135
- ctx.workStage === 'design';
136
-
137
- console.log('follow up icon code', icon);
138
- console.log('follow up icon value', getIconValue(icon));
139
- ctx.pickedIconValue = getIconValue(icon);
140
- }
141
-
142
- sendMessage(
143
- { text: title },
144
- {
145
- body: {
146
- stage: 'design',
147
- },
148
- }
149
- );
150
- }}
151
- headless
152
- />
153
- ) : null;
154
- }
155
-
156
- // save fields confirm
157
- if (isFieldsSaveConfirm) {
158
- const formInfo = plugin?.getCurrentWorkingForm() as RealFormInfo;
159
- evtBus.emit('form-builder-FieldsCreatedFinish', formInfo);
160
- return <>{fieldsConfirmed ? <FakeBotMessage>试试以下建议</FakeBotMessage> : null}</>;
161
- }
162
-
163
- const appendConfirmBtn =
164
- // TODO: 特殊文本解析在 node 端处理,前端只负责渲染
165
- part.text?.includes('【确认搭建');
166
-
167
- const isDesignDoc = part.text?.startsWith('待搭建表单信息');
30
+ const fieldsConfirmed = useFieldsConfirmed();
168
31
 
169
- return isDesignDoc ? (
170
- <DesignInfo designMarkdown={part.text} id={props.id}>
171
- {appendConfirmBtn ? (
172
- <CreateFormConfirm sendMessage={sendMessage} designDoc={part.text} />
173
- ) : null}
174
- </DesignInfo>
175
- ) : (
176
- <MarkdownMsgpart {...props}></MarkdownMsgpart>
177
- );
32
+ return <PartComp {...props} part={part} confirmed={fieldsConfirmed} />;
178
33
  };
@@ -0,0 +1,62 @@
1
+ import { MsgPartCompProps, RealFormInfo } from '@baishuyun/types';
2
+ import { IExtraPartProps, McpFormBuilderPluginCtx } from '../types';
3
+ import { FollowUp } from './follow-up';
4
+ import { TextUIPart } from 'ai';
5
+ import { usePluginCtx } from '@/hooks/use-plugin-ctx';
6
+ import { FormBuilderPlugin } from '..';
7
+ import { MCP_PLUGIN_NAME } from '../const';
8
+ import { getIconValue } from '@/lib/utils';
9
+ import { usePlugin } from '@/hooks/use-plugin';
10
+ import { FakeBotMessage } from '@/components/biz-comp/FakeBotMsg';
11
+ import { useEffect } from 'react';
12
+ import { useEvtBus } from '@/hooks/use-evt-bus';
13
+
14
+ export const SuggestionPrefixPart: React.FC<MsgPartCompProps & IExtraPartProps> = (props) => {
15
+ const { confirmed: fieldsConfirmed } = props;
16
+ const plugin = usePlugin<FormBuilderPlugin>(MCP_PLUGIN_NAME);
17
+ const formInfo = plugin?.getCurrentWorkingForm() as RealFormInfo;
18
+ const evtBus = useEvtBus();
19
+
20
+ useEffect(() => {
21
+ evtBus.emit('form-builder-FieldsCreatedFinish', formInfo);
22
+ }, []);
23
+
24
+ return <>{fieldsConfirmed ? <FakeBotMessage>试试以下建议</FakeBotMessage> : null}</>;
25
+ };
26
+
27
+ export const SuggestionPart: React.FC<MsgPartCompProps & IExtraPartProps> = (props) => {
28
+ const { confirmed, sendMessage, part: p } = props;
29
+ const part = p as TextUIPart;
30
+
31
+ const ctx = usePluginCtx<McpFormBuilderPluginCtx, FormBuilderPlugin>(MCP_PLUGIN_NAME);
32
+
33
+ if (!confirmed) {
34
+ return null;
35
+ }
36
+
37
+ return (
38
+ <FollowUp
39
+ title={part.text}
40
+ description={part.text}
41
+ onSelect={(title, icon) => {
42
+ if (ctx) {
43
+ ctx.workStage === 'design';
44
+
45
+ console.log('follow up icon code', icon);
46
+ console.log('follow up icon value', getIconValue(icon));
47
+ ctx.pickedIconValue = getIconValue(icon);
48
+ }
49
+
50
+ sendMessage(
51
+ { text: title },
52
+ {
53
+ body: {
54
+ stage: 'design',
55
+ },
56
+ }
57
+ );
58
+ }}
59
+ headless
60
+ />
61
+ );
62
+ };
@@ -0,0 +1,50 @@
1
+ import { TextUIPart } from 'ai';
2
+ import { usePlugin } from '@/hooks/use-plugin';
3
+ import { useEvtBus } from '@/hooks/use-evt-bus';
4
+ import { GetFieldJsonInfo, IsFieldsJsonPart } from '@/lib/utils';
5
+ import { FormBuilderPlugin } from '..';
6
+ import { MCP_PLUGIN_NAME } from '../const';
7
+ import { FieldValueCheckerProps } from '@/components/biz-comp/FieldValueChecker';
8
+ import { FieldIcon } from '@/components/biz-comp/field-icon';
9
+
10
+ export const useBuildFieldsData = (part: TextUIPart, fieldsConfirmed: boolean) => {
11
+ const isFieldsJson = IsFieldsJsonPart(part);
12
+ const fieldsParts = Array.isArray(part) && part.length ? part : isFieldsJson ? [part] : [];
13
+
14
+ const evtBus = useEvtBus();
15
+
16
+ const plugin = usePlugin<FormBuilderPlugin>(MCP_PLUGIN_NAME);
17
+
18
+ return fieldsParts
19
+ .map((p) => {
20
+ const field = GetFieldJsonInfo(p);
21
+
22
+ if (!field?.widget) {
23
+ return null;
24
+ }
25
+
26
+ return {
27
+ field,
28
+ disabled: fieldsConfirmed,
29
+ onLoaded: (field: any) => {
30
+ const finalField = plugin?.onBeforeFieldCreate(field);
31
+ evtBus.emit('form-builder-FieldCreated', {
32
+ field: finalField,
33
+ checked: true,
34
+ });
35
+ plugin?.onAfterFieldCreate(field);
36
+ },
37
+ icon: <FieldIcon type={field.widget?.type} />,
38
+ onChange: (check: boolean, field: any, parentFieldName?: string, index?: number) => {
39
+ console.log('field checked changed:', { check, field, parentFieldName, index });
40
+ evtBus.emit('form-builder-FieldCheckedChanged', {
41
+ field,
42
+ checked: check,
43
+ parentFieldName,
44
+ index,
45
+ });
46
+ },
47
+ };
48
+ })
49
+ .filter(Boolean) as Array<FieldValueCheckerProps>;
50
+ };
@@ -20,9 +20,10 @@ import {
20
20
  hasSubFields,
21
21
  hasLinkInfo,
22
22
  fieldProcessorFactory,
23
+ ensureCleanFormName,
23
24
  } from './utils';
24
25
  import { EVENTS } from '../form-builder-base-plugin/const';
25
- import { IsFieldsJsonPart, mergeConsecutiveTargets } from '@/lib/utils';
26
+ import { ensureEndSlash, IsFieldsJsonPart, mergeConsecutiveTargets } from '@/lib/utils';
26
27
  import { EntryButton } from './components/entry-btn';
27
28
  import { FormBuilderOpeningLines } from './components/opening-lines';
28
29
 
@@ -45,10 +46,6 @@ export class FormBuilderPlugin extends FormBuilderBasePlugin<McpFormBuilderPlugi
45
46
  OpeningLines: FormBuilderOpeningLines,
46
47
  };
47
48
 
48
- // clear cwf(current working form) when workStage is build, which means rebuild fields from scratch.
49
- // 1. clear fields.
50
- // 2. clear fieldMap.
51
- // 3. rebuild linkInfo based on rebuild fields?
52
49
  private clearCurrentWorkingForm = () => {
53
50
  if (this.Context.workStage !== 'build') {
54
51
  // 仅在搭建阶段清空当前表单信息
@@ -60,14 +57,6 @@ export class FormBuilderPlugin extends FormBuilderBasePlugin<McpFormBuilderPlugi
60
57
  return;
61
58
  }
62
59
 
63
- // 清空当前表单字段信息
64
- cwf.fields = [];
65
- cwf.fieldMap.clear();
66
-
67
- // TODO: 清空当前表单关联信息
68
- // cwf.designInfo.linkInfoMap.clear();
69
-
70
- // 触发字段清空事件,通知更新状态
71
60
  const evtBus = this._chatInstance?.eventBus;
72
61
  if (evtBus) {
73
62
  evtBus.emit<'form-builder-FieldsCleared'>(EVENTS.FIELDS_CLEARED, {});
@@ -76,15 +65,7 @@ export class FormBuilderPlugin extends FormBuilderBasePlugin<McpFormBuilderPlugi
76
65
 
77
66
  public lifecycleHooks?: Partial<PluginHooks> | undefined = {
78
67
  onBeforeMessagesClear: (conversationId) => {
79
- const req = async () => {
80
- await fetch(`https://agent.online-office.net/web/api/form/conversation/clear`, {
81
- method: 'POST',
82
- body: JSON.stringify({ conversationId }),
83
- });
84
- };
85
-
86
- req();
87
-
68
+ this.clearHistoryConversation(conversationId || '', this._chatInstance || undefined);
88
69
  this.Context.workStage = 'design';
89
70
  },
90
71
  onBeforeMessagePartsRender(parts: Array<part>) {
@@ -99,12 +80,20 @@ export class FormBuilderPlugin extends FormBuilderBasePlugin<McpFormBuilderPlugi
99
80
  body: {
100
81
  stage: this.Context.workStage,
101
82
  name: this.getCurrentWorkingForm()?.formName || text,
83
+ text,
102
84
  },
103
85
  },
104
86
  };
105
87
  },
106
- onAfterChatAreaHide({ clearMsgs }) {
88
+ onAfterChatAreaHide: ({ clearMsgs }) => {
107
89
  clearMsgs();
90
+
91
+ this.clearCurrentWorkingForm();
92
+
93
+ this.Context = {
94
+ formMap: new Map(),
95
+ workStage: 'design',
96
+ };
108
97
  },
109
98
  onBeforeChatRender: () => {
110
99
  return {
@@ -162,6 +151,24 @@ export class FormBuilderPlugin extends FormBuilderBasePlugin<McpFormBuilderPlugi
162
151
  }
163
152
  }
164
153
 
154
+ private clearHistoryConversation = async (conversationId: string, inst?: IChatSDK) => {
155
+ const apiEndpoint = inst?.options.backendApiEndpoint;
156
+ if (!apiEndpoint) {
157
+ console.error('Backend API endpoint is not defined in SDK options.');
158
+ return;
159
+ }
160
+
161
+ if (!conversationId) {
162
+ console.error('Conversation ID is required to clear history.');
163
+ return;
164
+ }
165
+
166
+ await fetch(`${ensureEndSlash(apiEndpoint)}form/conversation/clear`, {
167
+ method: 'POST',
168
+ body: JSON.stringify({ conversationId }),
169
+ });
170
+ };
171
+
165
172
  private enhanceField(field: Field) {
166
173
  const processorCreator = fieldProcessorFactory[field.widget.type as FieldType];
167
174
  if (!processorCreator) {
@@ -258,19 +265,17 @@ export class FormBuilderPlugin extends FormBuilderBasePlugin<McpFormBuilderPlugi
258
265
  this.Context.pickedIconValue = 33;
259
266
  };
260
267
 
261
- public onAfterFieldsSave(onFormProcessed: (processedForm: FormInfo) => void) {
268
+ public onAfterFieldsSave = (onFormProcessed: (processedForm: FormInfo) => void) => {
262
269
  // 取当前正在处理的表单 current working form
263
270
  const cwf = this.getCurrentWorkingForm();
264
271
  if (!cwf) {
265
272
  return;
266
273
  }
267
274
 
268
- // 上下文中表单字段遍历,识别需要回写的表单、字段
269
275
  formFieldsWalker(this.Context.formMap, {
270
276
  // 目标表单筛选
271
277
  isTargetForm: (formName: string, formInfo: FormInfo) => {
272
278
  if (formName === cwf.formName) {
273
- console.log('跳过自身表单');
274
279
  return false;
275
280
  }
276
281
 
@@ -284,16 +289,21 @@ export class FormBuilderPlugin extends FormBuilderBasePlugin<McpFormBuilderPlugi
284
289
 
285
290
  // 目标字段筛选
286
291
  isTargetField: (_: string, linkInfo: LinkInfo) => {
287
- // 如果目标字段关联了当前表单,则需要处理
288
- return linkInfo.targetFormName === cwf.formName;
292
+ return ensureCleanFormName(linkInfo.targetFormName) === ensureCleanFormName(cwf.formName!);
289
293
  },
290
294
 
291
295
  // 字段处理,补全关联信息
292
296
  fieldProcessor: (formInfo: FormInfo, field: Field, linkInfo: LinkInfo) => {
297
+ if (!field) {
298
+ console.log('[fieldProcessor] 字段信息不存在,跳过处理');
299
+ return;
300
+ }
301
+
293
302
  const fieldType = field.widget?.type as FieldType;
294
303
 
295
304
  // 没有对应的处理器,跳过
296
305
  if (!fieldProcessorFactory[fieldType]) {
306
+ console.log(`[fieldProcessor] 未找到${fieldType}类型的处理器,跳过处理`);
297
307
  return;
298
308
  }
299
309
 
@@ -307,7 +317,7 @@ export class FormBuilderPlugin extends FormBuilderBasePlugin<McpFormBuilderPlugi
307
317
 
308
318
  onFormProcessed,
309
319
  });
310
- }
320
+ };
311
321
 
312
322
  public getCurrentWorkingForm() {
313
323
  return this.Context.formMap.get(this.currentWorkingFormName);
@@ -324,7 +334,6 @@ export const FormBuilderPluginRegisterEntry: PluginRegistryEntry<McpFormBuilderP
324
334
  createContext: () => {
325
335
  return {
326
336
  formMap: new Map(),
327
-
328
337
  workStage: 'design', // 默认设计阶段
329
338
  };
330
339
  },
@@ -1,6 +1,6 @@
1
1
  import { FieldsTools } from '@baishuyun/agents';
2
- import { FormBuilderWorkStage, ValueOf } from '@baishuyun/types';
3
- import { ToolUIPart } from 'ai';
2
+ import { FormBuilderWorkStage, MsgPartCompProps, ValueOf } from '@baishuyun/types';
3
+ import { TextUIPart, ToolUIPart } from 'ai';
4
4
  import { DesignInfo } from './utils';
5
5
 
6
6
  export type Field = ValueOf<Pick<ToolUIPart<FieldsTools>, 'output'>>;
@@ -24,3 +24,20 @@ export interface McpFormBuilderPluginCtx {
24
24
 
25
25
  pickedIconValue?: number;
26
26
  }
27
+
28
+ export type FormBuildPartRenderStrategy =
29
+ | 'fields'
30
+ | 'followup'
31
+ | 'followup_prefix'
32
+ | 'design_doc'
33
+ | 'markdown'
34
+ | 'unknown';
35
+
36
+ export interface IExtraPartProps {
37
+ confirmed?: boolean;
38
+ part: TextUIPart;
39
+ }
40
+
41
+ export type FormBuildPartRenderStrategyMap = {
42
+ [key in FormBuildPartRenderStrategy]: React.FC<MsgPartCompProps & IExtraPartProps>;
43
+ };
@@ -0,0 +1,27 @@
1
+ import { IsFieldsJsonPart, IsSuggesstionPart, NeedToAppendFieldsSaveConfirm } from '@/lib/utils';
2
+ import { TextUIPart } from 'ai';
3
+
4
+ export const getRenderStrategy = (part: TextUIPart) => {
5
+ const isFieldsJson = IsFieldsJsonPart(part);
6
+ const fieldsParts = Array.isArray(part) && part.length ? part : isFieldsJson ? [part] : [];
7
+
8
+ if (fieldsParts.length) {
9
+ return 'fields';
10
+ }
11
+
12
+ if (IsSuggesstionPart(part)) {
13
+ return 'followup';
14
+ }
15
+
16
+ const isFieldsSaveConfirm = NeedToAppendFieldsSaveConfirm(part);
17
+ if (isFieldsSaveConfirm) {
18
+ return 'followup_prefix';
19
+ }
20
+
21
+ const isDesignDoc = part.text?.startsWith('待搭建表单信息');
22
+ if (isDesignDoc) {
23
+ return 'design_doc';
24
+ }
25
+
26
+ return 'markdown';
27
+ };