@fv-ui/ai-chat 0.4.0 → 0.7.0

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/lib/index.js CHANGED
@@ -3359,7 +3359,7 @@
3359
3359
  key: 1,
3360
3360
  class: "fv-editor-footer"
3361
3361
  };
3362
- const _hoisted_17 = { class: "fv-editor-select-dialog" };
3362
+ const _hoisted_17$1 = { class: "fv-editor-select-dialog" };
3363
3363
  const _hoisted_18 = { class: "fv-editor-select-title" };
3364
3364
  const _hoisted_19 = { class: "fv-editor-select-grid" };
3365
3365
  const _hoisted_20 = ["onClick"];
@@ -4322,7 +4322,7 @@
4322
4322
  onClose: closeSelectDialog
4323
4323
  }, {
4324
4324
  default: vue.withCtx(() => [
4325
- vue.createElementVNode("div", _hoisted_17, [
4325
+ vue.createElementVNode("div", _hoisted_17$1, [
4326
4326
  (vue.openBlock(true), vue.createElementBlock(
4327
4327
  vue.Fragment,
4328
4328
  null,
@@ -5631,6 +5631,7 @@
5631
5631
  role: node.role,
5632
5632
  content: node.content,
5633
5633
  reasoning: node.reasoning,
5634
+ toolSteps: node.toolSteps ? node.toolSteps.map((s) => ({ ...s })) : void 0,
5634
5635
  files: node.files ? [...node.files] : void 0,
5635
5636
  modelIdx: node.modelIdx,
5636
5637
  model: node.model,
@@ -5911,6 +5912,17 @@ ${fileParts.join("\n")}` });
5911
5912
  msgs.edit(assistantId, { backendId: id });
5912
5913
  },
5913
5914
  onTool: (ev) => {
5915
+ const steps = [...msgs.messages.value[assistantId]?.toolSteps ?? []];
5916
+ if (ev.status === "start") {
5917
+ steps.push({
5918
+ key: `${ev.toolName}-${steps.length}`,
5919
+ title: options.toolStepLabel ? options.toolStepLabel(ev.toolName) : ev.toolName,
5920
+ status: "loading"
5921
+ });
5922
+ } else if (steps.length) {
5923
+ steps[steps.length - 1] = { ...steps[steps.length - 1], status: "success" };
5924
+ }
5925
+ msgs.edit(assistantId, { toolSteps: steps });
5914
5926
  options.onToolEvent?.(ev);
5915
5927
  },
5916
5928
  onDone: () => {
@@ -6024,50 +6036,51 @@ ${fileParts.join("\n")}` });
6024
6036
  key: 0,
6025
6037
  class: "fv-msg-avatar"
6026
6038
  };
6027
- const _hoisted_3$3 = { class: "fv-msg-main" };
6028
- const _hoisted_4$2 = {
6039
+ const _hoisted_3$3 = ["src"];
6040
+ const _hoisted_4$2 = ["src"];
6041
+ const _hoisted_5 = { class: "fv-msg-main" };
6042
+ const _hoisted_6 = {
6029
6043
  key: 0,
6030
6044
  class: "fv-msg-header"
6031
6045
  };
6032
- const _hoisted_5 = { class: "fv-msg-role" };
6033
- const _hoisted_6 = {
6034
- key: 0,
6046
+ const _hoisted_7 = {
6047
+ key: 2,
6035
6048
  class: "fv-msg-model"
6036
6049
  };
6037
- const _hoisted_7 = {
6050
+ const _hoisted_8 = {
6038
6051
  key: 1,
6039
6052
  class: "fv-msg-files"
6040
6053
  };
6041
- const _hoisted_8 = ["src", "alt"];
6042
- const _hoisted_9 = {
6054
+ const _hoisted_9 = ["src", "alt"];
6055
+ const _hoisted_10 = {
6043
6056
  key: 1,
6044
6057
  class: "fv-msg-file-name"
6045
6058
  };
6046
- const _hoisted_10 = {
6047
- key: 3,
6059
+ const _hoisted_11 = {
6060
+ key: 4,
6048
6061
  class: "fv-msg-content"
6049
6062
  };
6050
- const _hoisted_11 = {
6063
+ const _hoisted_12 = {
6051
6064
  key: 0,
6052
6065
  class: "fv-msg-error"
6053
6066
  };
6054
- const _hoisted_12 = {
6067
+ const _hoisted_13 = {
6055
6068
  key: 2,
6056
6069
  class: "fv-msg-pending"
6057
6070
  };
6058
- const _hoisted_13 = {
6059
- key: 4,
6060
- class: "fv-msg-content fv-msg-content-user"
6061
- };
6062
6071
  const _hoisted_14 = {
6063
6072
  key: 5,
6064
- class: "fv-msg-actions"
6073
+ class: "fv-msg-content fv-msg-content-user"
6065
6074
  };
6066
6075
  const _hoisted_15 = {
6076
+ key: 6,
6077
+ class: "fv-msg-actions"
6078
+ };
6079
+ const _hoisted_16 = {
6067
6080
  key: 0,
6068
6081
  class: "fv-msg-branch"
6069
6082
  };
6070
- const _hoisted_16 = { class: "fv-msg-branch-label" };
6083
+ const _hoisted_17 = { class: "fv-msg-branch-label" };
6071
6084
  var _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
6072
6085
  ...{ name: "FvAiMessage" },
6073
6086
  __name: "index",
@@ -6078,6 +6091,12 @@ ${fileParts.join("\n")}` });
6078
6091
  showBranchSwitch: { type: Boolean, required: false, default: true },
6079
6092
  showUserAvatar: { type: Boolean, required: false, default: true },
6080
6093
  showUserName: { type: Boolean, required: false, default: true },
6094
+ showAssistantAvatar: { type: Boolean, required: false, default: true },
6095
+ showAssistantName: { type: Boolean, required: false, default: true },
6096
+ userAvatar: { type: String, required: false, default: "" },
6097
+ assistantAvatar: { type: String, required: false, default: "" },
6098
+ userName: { type: String, required: false, default: "" },
6099
+ assistantName: { type: String, required: false, default: "" },
6081
6100
  autoCollapse: { type: Boolean, required: false, default: true }
6082
6101
  },
6083
6102
  emits: ["copy", "regenerate", "branch-change"],
@@ -6092,6 +6111,19 @@ ${fileParts.join("\n")}` });
6092
6111
  return "end";
6093
6112
  });
6094
6113
  const hasReasoning = vue.computed(() => !!props.message.reasoning);
6114
+ const hasToolSteps = vue.computed(() => (props.message.toolSteps?.length ?? 0) > 0);
6115
+ const toolChainItems = vue.computed(() => {
6116
+ const steps = props.message.toolSteps ?? [];
6117
+ const running = props.message.status === "pending" || props.message.status === "streaming";
6118
+ return steps.map((s) => {
6119
+ const loading = running && s.status !== "error" && s.status !== "success";
6120
+ return {
6121
+ ...s,
6122
+ status: loading ? "loading" : s.status ?? "success",
6123
+ title: `${loading ? "\u6B63\u5728\u67E5\u8BE2" : "\u5DF2\u67E5\u8BE2"}${s.title ?? ""}`
6124
+ };
6125
+ });
6126
+ });
6095
6127
  const modelLabel = vue.computed(() => props.message.model ?? "");
6096
6128
  function onCopy() {
6097
6129
  emit("copy", props.message);
@@ -6108,50 +6140,70 @@ ${fileParts.join("\n")}` });
6108
6140
  class: vue.normalizeClass(["fv-msg", [`is-${__props.message.role}`, { "is-error": __props.message.status === "error", "is-user": isUser.value }]]),
6109
6141
  "data-message-id": __props.message.id
6110
6142
  }, [
6111
- vue.createCommentVNode(" \u5934\u50CF:user \u53F3\u4FA7(\u81EA\u8EAB),assistant \u5DE6\u4FA7;showUserAvatar=false \u65F6\u7528\u6237\u6D88\u606F\u4E0D\u6E32\u67D3 "),
6112
- !isUser.value || __props.showUserAvatar ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$3, [
6143
+ vue.createCommentVNode(" \u5934\u50CF:user \u53F3\u4FA7(\u81EA\u8EAB),assistant \u5DE6\u4FA7;\u663E\u9690\u5F00\u5173\u5173\u95ED\u65F6\u4E0D\u6E32\u67D3;\r\n \u4F18\u5148\u7EA7:message-avatar \u6574\u4F53\u63D2\u69FD > user-avatar/assistant-avatar \u7EC6\u5206\u63D2\u69FD > props \u56FE\u7247 > \u5185\u7F6E\u56FE\u6807 "),
6144
+ (isUser.value ? __props.showUserAvatar : __props.showAssistantAvatar) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$3, [
6113
6145
  vue.renderSlot(_ctx.$slots, "message-avatar", { message: __props.message }, () => [
6114
- isUser.value ? (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElIcon), {
6115
- key: 0,
6116
- class: "fv-msg-avatar-user"
6117
- }, {
6118
- default: vue.withCtx(() => [
6119
- vue.createVNode(vue.unref(ElementPlusIconsVue.User))
6120
- ]),
6121
- _: 1
6122
- /* STABLE */
6123
- })) : (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElIcon), {
6124
- key: 1,
6125
- class: "fv-msg-avatar-bot"
6126
- }, {
6127
- default: vue.withCtx(() => [
6128
- vue.createVNode(vue.unref(ElementPlusIconsVue.ChatDotRound))
6129
- ]),
6130
- _: 1
6131
- /* STABLE */
6132
- }))
6146
+ isUser.value ? vue.renderSlot(_ctx.$slots, "user-avatar", {}, () => [
6147
+ __props.userAvatar ? (vue.openBlock(), vue.createElementBlock("img", {
6148
+ key: 0,
6149
+ class: "fv-msg-avatar-img",
6150
+ src: __props.userAvatar,
6151
+ alt: ""
6152
+ }, null, 8, _hoisted_3$3)) : (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElIcon), {
6153
+ key: 1,
6154
+ class: "fv-msg-avatar-user"
6155
+ }, {
6156
+ default: vue.withCtx(() => [
6157
+ vue.createVNode(vue.unref(ElementPlusIconsVue.User))
6158
+ ]),
6159
+ _: 1
6160
+ /* STABLE */
6161
+ }))
6162
+ ], void 0, 0) : vue.renderSlot(_ctx.$slots, "assistant-avatar", {}, () => [
6163
+ __props.assistantAvatar ? (vue.openBlock(), vue.createElementBlock("img", {
6164
+ key: 0,
6165
+ class: "fv-msg-avatar-img",
6166
+ src: __props.assistantAvatar,
6167
+ alt: ""
6168
+ }, null, 8, _hoisted_4$2)) : (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElIcon), {
6169
+ key: 1,
6170
+ class: "fv-msg-avatar-bot"
6171
+ }, {
6172
+ default: vue.withCtx(() => [
6173
+ vue.createVNode(vue.unref(ElementPlusIconsVue.ChatDotRound))
6174
+ ]),
6175
+ _: 1
6176
+ /* STABLE */
6177
+ }))
6178
+ ], void 0, 1)
6133
6179
  ])
6134
6180
  ])) : vue.createCommentVNode("v-if", true),
6135
- vue.createElementVNode("div", _hoisted_3$3, [
6136
- vue.createCommentVNode(" \u5934\u90E8:\u89D2\u8272\u540D + \u6A21\u578B\u6807\u8BB0;showUserName=false \u65F6\u7528\u6237\u6D88\u606F\u4E0D\u6E32\u67D3 "),
6137
- !isUser.value || __props.showUserName ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$2, [
6138
- vue.createElementVNode(
6139
- "span",
6140
- _hoisted_5,
6141
- vue.toDisplayString(isUser.value ? "\u4F60" : "\u52A9\u624B"),
6142
- 1
6143
- /* TEXT */
6144
- ),
6181
+ vue.createElementVNode("div", _hoisted_5, [
6182
+ vue.createCommentVNode(" \u5934\u90E8:\u89D2\u8272\u540D + \u6A21\u578B\u6807\u8BB0;\u663E\u9690\u5F00\u5173\u5173\u95ED\u65F6\u4E0D\u6E32\u67D3;\u7EC6\u5206\u63D2\u69FD > props > \u9ED8\u8BA4\u6587\u6848 "),
6183
+ (isUser.value ? __props.showUserName : __props.showAssistantName) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_6, [
6184
+ isUser.value ? vue.renderSlot(_ctx.$slots, "user-name", { message: __props.message }, () => [
6185
+ vue.createTextVNode(
6186
+ vue.toDisplayString(__props.userName || "\u4F60"),
6187
+ 1
6188
+ /* TEXT */
6189
+ )
6190
+ ], void 0, 0) : vue.renderSlot(_ctx.$slots, "assistant-name", { message: __props.message }, () => [
6191
+ vue.createTextVNode(
6192
+ vue.toDisplayString(__props.assistantName || "\u52A9\u624B"),
6193
+ 1
6194
+ /* TEXT */
6195
+ )
6196
+ ], void 0, 1),
6145
6197
  !isUser.value && modelLabel.value ? (vue.openBlock(), vue.createElementBlock(
6146
6198
  "span",
6147
- _hoisted_6,
6199
+ _hoisted_7,
6148
6200
  vue.toDisplayString(modelLabel.value),
6149
6201
  1
6150
6202
  /* TEXT */
6151
6203
  )) : vue.createCommentVNode("v-if", true)
6152
6204
  ])) : vue.createCommentVNode("v-if", true),
6153
6205
  vue.createCommentVNode(" \u9644\u4EF6:user \u6D88\u606F files \u4EE5 FilesCard \u5E73\u94FA "),
6154
- __props.message.files?.length ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_7, [
6206
+ __props.message.files?.length ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_8, [
6155
6207
  vue.renderSlot(_ctx.$slots, "message-files", {
6156
6208
  message: __props.message,
6157
6209
  files: __props.message.files
@@ -6172,9 +6224,9 @@ ${fileParts.join("\n")}` });
6172
6224
  class: "fv-msg-file-img",
6173
6225
  src: f.url,
6174
6226
  alt: f.name
6175
- }, null, 8, _hoisted_8)) : (vue.openBlock(), vue.createElementBlock(
6227
+ }, null, 8, _hoisted_9)) : (vue.openBlock(), vue.createElementBlock(
6176
6228
  "span",
6177
- _hoisted_9,
6229
+ _hoisted_10,
6178
6230
  vue.toDisplayString(f.name),
6179
6231
  1
6180
6232
  /* TEXT */
@@ -6189,9 +6241,15 @@ ${fileParts.join("\n")}` });
6189
6241
  ))
6190
6242
  ])
6191
6243
  ])) : vue.createCommentVNode("v-if", true),
6244
+ vue.createCommentVNode(" \u5DE5\u5177\u8C03\u7528\u8F68\u8FF9(assistant \u542B toolSteps \u65F6):\u7EB5\u5411\u6B65\u9AA4\u94FE,Thinking \u4E4B\u4E0B\u6B63\u6587\u4E4B\u4E0A "),
6245
+ !isUser.value && hasToolSteps.value ? (vue.openBlock(), vue.createBlock(_sfc_main$9, {
6246
+ key: 2,
6247
+ class: "fv-msg-tools",
6248
+ items: toolChainItems.value
6249
+ }, null, 8, ["items"])) : vue.createCommentVNode("v-if", true),
6192
6250
  vue.createCommentVNode(" \u601D\u8003\u94FE\u6298\u53E0(assistant \u542B reasoning \u65F6) "),
6193
6251
  !isUser.value && hasReasoning.value ? (vue.openBlock(), vue.createBlock(_sfc_main$a, {
6194
- key: 2,
6252
+ key: 3,
6195
6253
  content: __props.message.reasoning,
6196
6254
  status: thinkingStatus.value,
6197
6255
  "auto-collapse": __props.autoCollapse
@@ -6205,17 +6263,17 @@ ${fileParts.join("\n")}` });
6205
6263
  /* STABLE */
6206
6264
  }, 8, ["content", "status", "auto-collapse"])) : vue.createCommentVNode("v-if", true),
6207
6265
  vue.createCommentVNode(" \u6B63\u6587:user \u7EAF\u6587\u672C\u6C14\u6CE1;assistant Markdown;pending \u7A7A\u5185\u5BB9\u7ED9\u52A0\u8F7D\u5360\u4F4D "),
6208
- !isUser.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_10, [
6266
+ !isUser.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_11, [
6209
6267
  __props.message.status === "error" ? (vue.openBlock(), vue.createElementBlock(
6210
6268
  "span",
6211
- _hoisted_11,
6269
+ _hoisted_12,
6212
6270
  vue.toDisplayString(__props.message.error || "\u751F\u6210\u5931\u8D25"),
6213
6271
  1
6214
6272
  /* TEXT */
6215
6273
  )) : __props.message.content ? (vue.openBlock(), vue.createBlock(_sfc_main$i, {
6216
6274
  key: 1,
6217
6275
  content: __props.message.content
6218
- }, null, 8, ["content"])) : __props.message.status === "pending" || __props.message.status === "streaming" ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_12, [
6276
+ }, null, 8, ["content"])) : __props.message.status === "pending" || __props.message.status === "streaming" ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_13, [
6219
6277
  (vue.openBlock(), vue.createElementBlock(
6220
6278
  vue.Fragment,
6221
6279
  null,
@@ -6238,13 +6296,13 @@ ${fileParts.join("\n")}` });
6238
6296
  ])) : vue.createCommentVNode("v-if", true)
6239
6297
  ])) : (vue.openBlock(), vue.createElementBlock(
6240
6298
  "div",
6241
- _hoisted_13,
6299
+ _hoisted_14,
6242
6300
  vue.toDisplayString(__props.message.content),
6243
6301
  1
6244
6302
  /* TEXT */
6245
6303
  )),
6246
6304
  vue.createCommentVNode(" \u64CD\u4F5C\u533A:assistant \u590D\u5236/\u91CD\u751F\u6210 + \u5206\u652F\u5207\u6362;user \u4EC5\u590D\u5236(hover \u6D88\u606F\u65F6\u6D6E\u73B0,\u89C1 scss) "),
6247
- __props.showActions || __props.showBranchSwitch && __props.branch && __props.branch.count > 1 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_14, [
6305
+ __props.showActions || __props.showBranchSwitch && __props.branch && __props.branch.count > 1 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_15, [
6248
6306
  vue.renderSlot(_ctx.$slots, "message-actions", { message: __props.message }, () => [
6249
6307
  __props.showActions && isUser.value ? (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElTooltip), {
6250
6308
  key: 0,
@@ -6335,7 +6393,7 @@ ${fileParts.join("\n")}` });
6335
6393
  })) : vue.createCommentVNode("v-if", true)
6336
6394
  ]),
6337
6395
  vue.createCommentVNode(" \u5206\u652F\u5207\u6362:\u5144\u5F1F\u5206\u652F > 1 \u65F6 "),
6338
- __props.showBranchSwitch && __props.branch && __props.branch.count > 1 ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_15, [
6396
+ __props.showBranchSwitch && __props.branch && __props.branch.count > 1 ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_16, [
6339
6397
  vue.createVNode(vue.unref(elementPlus.ElButton), {
6340
6398
  text: "",
6341
6399
  size: "small",
@@ -6358,7 +6416,7 @@ ${fileParts.join("\n")}` });
6358
6416
  }, 8, ["disabled"]),
6359
6417
  vue.createElementVNode(
6360
6418
  "span",
6361
- _hoisted_16,
6419
+ _hoisted_17,
6362
6420
  vue.toDisplayString(__props.branch.index) + " / " + vue.toDisplayString(__props.branch.count),
6363
6421
  1
6364
6422
  /* TEXT */
@@ -6409,10 +6467,18 @@ ${fileParts.join("\n")}` });
6409
6467
  suggestions: { type: Array, required: false, default: () => [] },
6410
6468
  suggestionsTitle: { type: String, required: false, default: "" },
6411
6469
  scrollThreshold: { type: Number, required: false, default: 40 },
6470
+ showScrollButton: { type: Boolean, required: false, default: true },
6471
+ scrollButtonThreshold: { type: Number, required: false, default: 100 },
6412
6472
  showActions: { type: Boolean, required: false, default: true },
6413
6473
  showBranchSwitch: { type: Boolean, required: false, default: true },
6414
6474
  showUserAvatar: { type: Boolean, required: false, default: true },
6415
- showUserName: { type: Boolean, required: false, default: true }
6475
+ showUserName: { type: Boolean, required: false, default: true },
6476
+ showAssistantAvatar: { type: Boolean, required: false, default: true },
6477
+ showAssistantName: { type: Boolean, required: false, default: true },
6478
+ userAvatar: { type: String, required: false, default: "" },
6479
+ assistantAvatar: { type: String, required: false, default: "" },
6480
+ userName: { type: String, required: false, default: "" },
6481
+ assistantName: { type: String, required: false, default: "" }
6416
6482
  },
6417
6483
  emits: ["select", "copy", "regenerate", "branch-change"],
6418
6484
  setup(__props, { expose: __expose, emit: __emit }) {
@@ -6437,8 +6503,14 @@ ${fileParts.join("\n")}` });
6437
6503
  function scrollToBottomIfNear() {
6438
6504
  if (distanceFromBottom() <= props.scrollThreshold) vue.nextTick(() => scrollToBottom());
6439
6505
  }
6506
+ const isAwayFromBottom = vue.ref(false);
6507
+ function onScroll() {
6508
+ isAwayFromBottom.value = distanceFromBottom() > props.scrollButtonThreshold;
6509
+ }
6510
+ vue.watch(() => props.scrollButtonThreshold, onScroll);
6440
6511
  vue.onMounted(() => {
6441
6512
  if (!isEmpty.value) vue.nextTick(() => scrollToBottom(false));
6513
+ onScroll();
6442
6514
  });
6443
6515
  vue.watch(() => props.messages.length, (nv, ov) => {
6444
6516
  if (nv > (ov ?? 0)) scrollToBottomIfNear();
@@ -6515,7 +6587,8 @@ ${fileParts.join("\n")}` });
6515
6587
  {
6516
6588
  ref_key: "scrollRef",
6517
6589
  ref: scrollRef,
6518
- class: "fv-messages-scroll"
6590
+ class: "fv-messages-scroll",
6591
+ onScrollPassive: onScroll
6519
6592
  },
6520
6593
  [
6521
6594
  vue.createElementVNode("div", _hoisted_3$2, [
@@ -6531,6 +6604,12 @@ ${fileParts.join("\n")}` });
6531
6604
  "show-branch-switch": __props.showBranchSwitch,
6532
6605
  "show-user-avatar": __props.showUserAvatar,
6533
6606
  "show-user-name": __props.showUserName,
6607
+ "show-assistant-avatar": __props.showAssistantAvatar,
6608
+ "show-assistant-name": __props.showAssistantName,
6609
+ "user-avatar": __props.userAvatar,
6610
+ "assistant-avatar": __props.assistantAvatar,
6611
+ "user-name": __props.userName,
6612
+ "assistant-name": __props.assistantName,
6534
6613
  onCopy,
6535
6614
  onRegenerate,
6536
6615
  onBranchChange: onBranch
@@ -6551,16 +6630,77 @@ ${fileParts.join("\n")}` });
6551
6630
  vue.renderSlot(_ctx.$slots, "message-actions", vue.mergeProps({ ref_for: true }, scope))
6552
6631
  ]),
6553
6632
  key: "1"
6633
+ } : void 0,
6634
+ _ctx.$slots["user-avatar"] ? {
6635
+ name: "user-avatar",
6636
+ fn: vue.withCtx(() => [
6637
+ vue.renderSlot(_ctx.$slots, "user-avatar")
6638
+ ]),
6639
+ key: "2"
6640
+ } : void 0,
6641
+ _ctx.$slots["assistant-avatar"] ? {
6642
+ name: "assistant-avatar",
6643
+ fn: vue.withCtx(() => [
6644
+ vue.renderSlot(_ctx.$slots, "assistant-avatar")
6645
+ ]),
6646
+ key: "3"
6647
+ } : void 0,
6648
+ _ctx.$slots["user-name"] ? {
6649
+ name: "user-name",
6650
+ fn: vue.withCtx((scope) => [
6651
+ vue.renderSlot(_ctx.$slots, "user-name", vue.mergeProps({ ref_for: true }, scope))
6652
+ ]),
6653
+ key: "4"
6654
+ } : void 0,
6655
+ _ctx.$slots["assistant-name"] ? {
6656
+ name: "assistant-name",
6657
+ fn: vue.withCtx((scope) => [
6658
+ vue.renderSlot(_ctx.$slots, "assistant-name", vue.mergeProps({ ref_for: true }, scope))
6659
+ ]),
6660
+ key: "5"
6554
6661
  } : void 0
6555
- ]), 1032, ["message", "branch", "show-actions", "show-branch-switch", "show-user-avatar", "show-user-name"]);
6662
+ ]), 1032, ["message", "branch", "show-actions", "show-branch-switch", "show-user-avatar", "show-user-name", "show-assistant-avatar", "show-assistant-name", "user-avatar", "assistant-avatar", "user-name", "assistant-name"]);
6556
6663
  }),
6557
6664
  128
6558
6665
  /* KEYED_FRAGMENT */
6559
- ))
6666
+ )),
6667
+ vue.createCommentVNode(" \u6EDA\u5230\u5E95\u90E8\u60AC\u6D6E\u6309\u94AE:\u5728 fv-messages-inner \u5185,\u968F\u5185\u5BB9\u5BBD\u5EA6\u7EA6\u675F\u5C42\u5B9A\u4F4D(\u5BBD\u5C4F\u65F6\u4E0D\u8D34\u89C6\u53E3\u53F3\u7F18);\r\n \u8DDD\u5E95\u8D85\u8FC7 scrollButtonThreshold \u663E\u793A(\u7A7A\u6001\u4E0D\u6E32\u67D3);\r\n scroll-button \u63D2\u69FD\u6574\u4F53\u8986\u76D6\u6309\u94AE,scroll-button-icon \u63D2\u69FD\u4EC5\u8986\u76D6\u56FE\u6807\u5185\u5BB9 "),
6668
+ vue.createVNode(vue.Transition, { name: "fv-messages-back-fade" }, {
6669
+ default: vue.withCtx(() => [
6670
+ vue.renderSlot(_ctx.$slots, "scroll-button", {
6671
+ scrollToBottom,
6672
+ awayFromBottom: isAwayFromBottom.value
6673
+ }, () => [
6674
+ __props.showScrollButton && !isEmpty.value && isAwayFromBottom.value ? (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElButton), {
6675
+ key: 0,
6676
+ class: "fv-messages-back",
6677
+ circle: "",
6678
+ "aria-label": "\u6EDA\u52A8\u5230\u5E95\u90E8",
6679
+ onClick: _cache[0] || (_cache[0] = ($event) => scrollToBottom())
6680
+ }, {
6681
+ default: vue.withCtx(() => [
6682
+ vue.createVNode(vue.unref(elementPlus.ElIcon), { class: "fv-messages-back-icon" }, {
6683
+ default: vue.withCtx(() => [
6684
+ vue.renderSlot(_ctx.$slots, "scroll-button-icon", {}, () => [
6685
+ vue.createVNode(vue.unref(ElementPlusIconsVue.Bottom))
6686
+ ])
6687
+ ]),
6688
+ _: 3
6689
+ /* FORWARDED */
6690
+ })
6691
+ ]),
6692
+ _: 3
6693
+ /* FORWARDED */
6694
+ })) : vue.createCommentVNode("v-if", true)
6695
+ ])
6696
+ ]),
6697
+ _: 3
6698
+ /* FORWARDED */
6699
+ })
6560
6700
  ])
6561
6701
  ],
6562
- 512
6563
- /* NEED_PATCH */
6702
+ 544
6703
+ /* NEED_HYDRATION, NEED_PATCH */
6564
6704
  )
6565
6705
  ],
6566
6706
  2112
@@ -6845,9 +6985,18 @@ ${fileParts.join("\n")}` });
6845
6985
  title: { type: String, required: false, default: "" },
6846
6986
  showHeader: { type: Boolean, required: false, default: false },
6847
6987
  centerWelcome: { type: Boolean, required: false, default: true },
6988
+ showScrollButton: { type: Boolean, required: false, default: true },
6989
+ scrollButtonThreshold: { type: Number, required: false, default: 100 },
6848
6990
  showUserAvatar: { type: Boolean, required: false, default: true },
6849
6991
  showUserName: { type: Boolean, required: false, default: true },
6992
+ showAssistantAvatar: { type: Boolean, required: false, default: true },
6993
+ showAssistantName: { type: Boolean, required: false, default: true },
6994
+ userAvatar: { type: String, required: false, default: "" },
6995
+ assistantAvatar: { type: String, required: false, default: "" },
6996
+ userName: { type: String, required: false, default: "" },
6997
+ assistantName: { type: String, required: false, default: "" },
6850
6998
  placeholder: { type: String, required: false, default: "" },
6999
+ toolStepLabel: { type: Function, required: false, default: void 0 },
6851
7000
  senderShadow: { type: Boolean, required: false, default: true },
6852
7001
  suggestions: { type: Array, required: false, default: () => [] },
6853
7002
  features: { type: Object, required: false, default: () => ({}) },
@@ -6891,6 +7040,7 @@ ${fileParts.join("\n")}` });
6891
7040
  adapter: resolveAdapter,
6892
7041
  models: () => isMultiple.value && selectedModels.value.length ? selectedModels.value : [""],
6893
7042
  initial: { messages: initialTable, currentId: initialId },
7043
+ toolStepLabel: props.toolStepLabel,
6894
7044
  onToolEvent: (ev) => emit("tool-event", ev)
6895
7045
  });
6896
7046
  const { send, stop: stopChat, regenerate: regenerateChat, msgs, isLoading } = chat;
@@ -7110,8 +7260,16 @@ ${fileParts.join("\n")}` });
7110
7260
  nodes: vue.unref(nodeTable),
7111
7261
  name: __props.title,
7112
7262
  suggestions: __props.suggestions,
7263
+ "show-scroll-button": __props.showScrollButton,
7264
+ "scroll-button-threshold": __props.scrollButtonThreshold,
7113
7265
  "show-user-avatar": __props.showUserAvatar,
7114
7266
  "show-user-name": __props.showUserName,
7267
+ "show-assistant-avatar": __props.showAssistantAvatar,
7268
+ "show-assistant-name": __props.showAssistantName,
7269
+ "user-avatar": __props.userAvatar,
7270
+ "assistant-avatar": __props.assistantAvatar,
7271
+ "user-name": __props.userName,
7272
+ "assistant-name": __props.assistantName,
7115
7273
  onSelect: onSelectSuggestion,
7116
7274
  onCopy,
7117
7275
  onRegenerate,
@@ -7134,14 +7292,56 @@ ${fileParts.join("\n")}` });
7134
7292
  ]),
7135
7293
  key: "1"
7136
7294
  } : void 0,
7295
+ _ctx.$slots["user-avatar"] ? {
7296
+ name: "user-avatar",
7297
+ fn: vue.withCtx(() => [
7298
+ vue.renderSlot(_ctx.$slots, "user-avatar")
7299
+ ]),
7300
+ key: "2"
7301
+ } : void 0,
7302
+ _ctx.$slots["assistant-avatar"] ? {
7303
+ name: "assistant-avatar",
7304
+ fn: vue.withCtx(() => [
7305
+ vue.renderSlot(_ctx.$slots, "assistant-avatar")
7306
+ ]),
7307
+ key: "3"
7308
+ } : void 0,
7309
+ _ctx.$slots["user-name"] ? {
7310
+ name: "user-name",
7311
+ fn: vue.withCtx((scope) => [
7312
+ vue.renderSlot(_ctx.$slots, "user-name", vue.normalizeProps(vue.guardReactiveProps(scope)))
7313
+ ]),
7314
+ key: "4"
7315
+ } : void 0,
7316
+ _ctx.$slots["assistant-name"] ? {
7317
+ name: "assistant-name",
7318
+ fn: vue.withCtx((scope) => [
7319
+ vue.renderSlot(_ctx.$slots, "assistant-name", vue.normalizeProps(vue.guardReactiveProps(scope)))
7320
+ ]),
7321
+ key: "5"
7322
+ } : void 0,
7137
7323
  _ctx.$slots.empty ? {
7138
7324
  name: "empty",
7139
7325
  fn: vue.withCtx(() => [
7140
7326
  vue.renderSlot(_ctx.$slots, "empty")
7141
7327
  ]),
7142
- key: "2"
7328
+ key: "6"
7329
+ } : void 0,
7330
+ _ctx.$slots["scroll-button"] ? {
7331
+ name: "scroll-button",
7332
+ fn: vue.withCtx((scope) => [
7333
+ vue.renderSlot(_ctx.$slots, "scroll-button", vue.normalizeProps(vue.guardReactiveProps(scope)))
7334
+ ]),
7335
+ key: "7"
7336
+ } : void 0,
7337
+ _ctx.$slots["scroll-button-icon"] ? {
7338
+ name: "scroll-button-icon",
7339
+ fn: vue.withCtx(() => [
7340
+ vue.renderSlot(_ctx.$slots, "scroll-button-icon")
7341
+ ]),
7342
+ key: "8"
7143
7343
  } : void 0
7144
- ]), 1032, ["messages", "nodes", "name", "suggestions", "show-user-avatar", "show-user-name"]),
7344
+ ]), 1032, ["messages", "nodes", "name", "suggestions", "show-scroll-button", "scroll-button-threshold", "show-user-avatar", "show-user-name", "show-assistant-avatar", "show-assistant-name", "user-avatar", "assistant-avatar", "user-name", "assistant-name"]),
7145
7345
  __props.features?.artifacts && artifacts.value.length ? (vue.openBlock(), vue.createBlock(_sfc_main$1, {
7146
7346
  key: 0,
7147
7347
  artifacts: artifacts.value,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fv-ui/ai-chat",
3
- "version": "0.4.0",
3
+ "version": "0.7.0",
4
4
  "description": "基于 Vue3 + Element Plus 的 AI 对话组件库",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",