@veltra/ai 2.0.0 → 2.1.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.
Files changed (70) hide show
  1. package/dist/chat/index.d.ts +2 -2
  2. package/dist/chat/transports/openai.js +1 -1
  3. package/dist/chat/transports/openai.js.map +1 -1
  4. package/dist/chat/types.d.ts +37 -2
  5. package/dist/chat/use-chat.d.ts +23 -1
  6. package/dist/chat/use-chat.js +91 -10
  7. package/dist/chat/use-chat.js.map +1 -1
  8. package/dist/components/ai-chat/ai-chat.js +207 -46
  9. package/dist/components/ai-chat/ai-chat.js.map +1 -1
  10. package/dist/components/ai-chat/chat-input.js +37 -12
  11. package/dist/components/ai-chat/chat-input.js.map +1 -1
  12. package/dist/components/ai-chat/di.js.map +1 -1
  13. package/dist/components/ai-chat/message-item.js +101 -23
  14. package/dist/components/ai-chat/message-item.js.map +1 -1
  15. package/dist/components/ai-chat/message-list.js +217 -32
  16. package/dist/components/ai-chat/message-list.js.map +1 -1
  17. package/dist/components/ai-chat/model-picker.js +69 -46
  18. package/dist/components/ai-chat/model-picker.js.map +1 -1
  19. package/dist/components/ai-chat/queue-list.js +70 -0
  20. package/dist/components/ai-chat/queue-list.js.map +1 -0
  21. package/dist/components/ai-chat/side-panel.js +96 -0
  22. package/dist/components/ai-chat/side-panel.js.map +1 -0
  23. package/dist/components/ai-chat/style.d.ts +4 -0
  24. package/dist/components/ai-chat/style.js +4 -0
  25. package/dist/components/ai-chat/style2.css +457 -74
  26. package/dist/components/ai-chat/tool-call.js +60 -26
  27. package/dist/components/ai-chat/tool-call.js.map +1 -1
  28. package/dist/components/ai-orb/ai-orb.js +94 -0
  29. package/dist/components/ai-orb/ai-orb.js.map +1 -0
  30. package/dist/components/ai-orb/orb-renderer.js +411 -0
  31. package/dist/components/ai-orb/orb-renderer.js.map +1 -0
  32. package/dist/components/ai-orb/style.d.ts +1 -0
  33. package/dist/components/ai-orb/style.js +1 -0
  34. package/dist/components/ai-orb/style2.css +23 -0
  35. package/dist/index.d.ts +4 -2
  36. package/dist/index.js +2 -1
  37. package/dist/style.js +1 -0
  38. package/dist/types/ai-chat.d.ts +21 -7
  39. package/dist/types/ai-orb.d.ts +27 -0
  40. package/dist/types/index.d.ts +2 -1
  41. package/package.json +5 -5
  42. package/src/chat/__test__/use-chat.test.ts +266 -13
  43. package/src/chat/transports/__test__/openai.test.ts +78 -0
  44. package/src/chat/transports/openai.ts +2 -2
  45. package/src/chat/types.ts +37 -1
  46. package/src/chat/use-chat.ts +120 -11
  47. package/src/components/ai-chat/__test__/ai-chat.test.ts +628 -12
  48. package/src/components/ai-chat/ai-chat.vue +227 -31
  49. package/src/components/ai-chat/chat-input.vue +41 -11
  50. package/src/components/ai-chat/di.ts +2 -0
  51. package/src/components/ai-chat/message-item.vue +98 -11
  52. package/src/components/ai-chat/message-list.vue +261 -21
  53. package/src/components/ai-chat/model-picker.vue +110 -59
  54. package/src/components/ai-chat/queue-list.vue +63 -0
  55. package/src/components/ai-chat/side-panel.vue +76 -0
  56. package/src/components/ai-chat/style.scss +527 -74
  57. package/src/components/ai-chat/style.ts +4 -0
  58. package/src/components/ai-chat/tool-call.vue +86 -42
  59. package/src/components/ai-orb/__test__/ai-orb.test.ts +251 -0
  60. package/src/components/ai-orb/ai-orb.vue +107 -0
  61. package/src/components/ai-orb/index.ts +1 -0
  62. package/src/components/ai-orb/orb-renderer.ts +505 -0
  63. package/src/components/ai-orb/style.scss +10 -0
  64. package/src/components/ai-orb/style.ts +1 -0
  65. package/src/components/index.ts +1 -0
  66. package/src/style.ts +1 -0
  67. package/src/tools/ask-question/__test__/ask-question.test.ts +1 -1
  68. package/src/types/ai-chat.ts +21 -6
  69. package/src/types/ai-orb.ts +27 -0
  70. package/src/types/index.ts +1 -0
@@ -1,11 +1,12 @@
1
1
  import { AiChatDIKey } from "./di.js";
2
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, mergeModels, nextTick, normalizeClass, openBlock, ref, renderList, toDisplayString, unref, useModel, useTemplateRef, withCtx } from "vue";
3
- import { ArrowDown, ArrowRight, Check } from "@veltra/icons/normal";
2
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, inject, mergeModels, nextTick, normalizeClass, openBlock, renderList, shallowRef, toDisplayString, unref, useModel, useTemplateRef, withCtx, withModifiers } from "vue";
3
+ import { ArrowDown, Check } from "@veltra/icons/normal";
4
4
  import { UDropdown, UIcon } from "@veltra/desktop";
5
5
  import { bem } from "@veltra/utils";
6
6
  //#region src/components/ai-chat/model-picker.vue
7
7
  const _hoisted_1 = ["onClick"];
8
8
  const _hoisted_2 = ["onClick"];
9
+ const _hoisted_3 = ["onClick"];
9
10
  const _sfc_main = /*@__PURE__*/ defineComponent({
10
11
  name: "UAiChatModelPicker",
11
12
  __name: "model-picker",
@@ -22,27 +23,46 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
22
23
  const reasoningLevel = useModel(__props, "reasoningLevel");
23
24
  const cls = inject(AiChatDIKey)?.cls ?? bem("ai-chat");
24
25
  const dropdownRef = useTemplateRef("dropdownRef");
25
- /** 思考强度子列表是否展开 */
26
- const reasoningExpanded = ref(false);
26
+ /** 当前内联展开思考强度的模型 id(手风琴,同时只展开一个) */
27
+ const expandedReasoningId = shallowRef();
27
28
  const currentModel = computed(() => {
28
29
  return props.models.find((m) => m.id === model.value);
29
30
  });
30
- const reasoningLevels = computed(() => currentModel.value?.reasoningLevels ?? []);
31
31
  const currentReasoningLabel = computed(() => {
32
- return reasoningLevels.value.find((l) => l.value === reasoningLevel.value)?.label;
32
+ return currentModel.value?.reasoningLevels?.find((level) => level.value === reasoningLevel.value)?.label;
33
33
  });
34
- /** 展开/收起思考强度子列表,并重置面板位置防止溢出 */
35
- const toggleReasoning = () => {
36
- reasoningExpanded.value = !reasoningExpanded.value;
37
- nextTick(() => dropdownRef.value?.updateDropdown());
34
+ /** 取模型默认推理等级:显式配置优先,缺省落到首个可选等级 */
35
+ const resolveDefaultReasoningLevel = (item) => {
36
+ const levels = item.reasoningLevels ?? [];
37
+ if (!levels.length) return void 0;
38
+ return levels.find((level) => level.value === item.defaultReasoningLevel)?.value ?? levels[0]?.value;
39
+ };
40
+ /** 胶囊文案:已选中模型展示当前推理等级,其余展示该模型的默认等级 */
41
+ const getReasoningLabel = (item) => {
42
+ if (item.id === model.value && currentReasoningLabel.value) return currentReasoningLabel.value;
43
+ return item.reasoningLevels?.find((level) => level.value === resolveDefaultReasoningLevel(item))?.label;
44
+ };
45
+ const isReasoningActive = (item, value) => {
46
+ return item.id === model.value && reasoningLevel.value === value;
47
+ };
48
+ /** 关闭时收起内联思考强度,下次打开仍从模型列表开始 */
49
+ const handleVisibleChange = (visible) => {
50
+ if (!visible) expandedReasoningId.value = void 0;
38
51
  };
39
- /** 选中模型(推理等级校正在 useChat 中完成) */
40
- const handleSelectModel = (id) => {
41
- model.value = id;
42
- reasoningExpanded.value = false;
52
+ /** 点击模型主体:直接选中模型,并同步到该模型默认推理等级 */
53
+ const handleSelectModel = (item) => {
54
+ model.value = item.id;
55
+ reasoningLevel.value = resolveDefaultReasoningLevel(item);
43
56
  dropdownRef.value?.close();
44
57
  };
45
- const handleSelectReasoning = (value) => {
58
+ /** 点击推理等级胶囊:内联展开/收起该模型的思考强度 */
59
+ const toggleReasoning = (item) => {
60
+ expandedReasoningId.value = expandedReasoningId.value === item.id ? void 0 : item.id;
61
+ nextTick(() => dropdownRef.value?.updateDropdown());
62
+ };
63
+ /** 选中思考强度:同时切到该等级所属模型,避免模型与推理等级错配 */
64
+ const handleSelectReasoning = (item, value) => {
65
+ model.value = item.id;
46
66
  reasoningLevel.value = value;
47
67
  dropdownRef.value?.close();
48
68
  };
@@ -51,8 +71,10 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
51
71
  ref_key: "dropdownRef",
52
72
  ref: dropdownRef,
53
73
  trigger: "click",
74
+ width: "auto",
54
75
  "min-width": "220px",
55
- "content-class": unref(cls).e("model-panel")
76
+ "content-class": unref(cls).e("model-panel"),
77
+ "onUpdate:visible": handleVisibleChange
56
78
  }, {
57
79
  trigger: withCtx(() => [createElementVNode("button", {
58
80
  type: "button",
@@ -68,44 +90,45 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
68
90
  _: 1
69
91
  }, 8, ["class"])
70
92
  ], 2)]),
71
- content: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.models, (item) => {
93
+ content: withCtx(() => [createElementVNode("div", { class: normalizeClass(unref(cls).e("model-panel-list")) }, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.models, (item) => {
72
94
  return openBlock(), createElementBlock("div", {
73
95
  key: item.id,
74
- class: normalizeClass([unref(cls).e("model-option"), unref(bem).is("active", item.id === model.value)]),
75
- onClick: ($event) => handleSelectModel(item.id)
76
- }, [createElementVNode("div", { class: normalizeClass(unref(cls).e("model-option-head")) }, [createElementVNode("span", null, toDisplayString(item.label ?? item.id), 1), item.id === model.value ? (openBlock(), createBlock(unref(UIcon), {
77
- key: 0,
78
- class: normalizeClass(unref(cls).e("model-option-check"))
79
- }, {
80
- default: withCtx(() => [createVNode(unref(Check))]),
81
- _: 1
82
- }, 8, ["class"])) : createCommentVNode("v-if", true)], 2), item.description ? (openBlock(), createElementBlock("div", {
96
+ class: normalizeClass([unref(cls).e("model-option"), unref(bem).is("active", item.id === model.value)])
97
+ }, [createElementVNode("div", {
98
+ class: normalizeClass(unref(cls).e("model-option-main")),
99
+ onClick: ($event) => handleSelectModel(item)
100
+ }, [createElementVNode("div", { class: normalizeClass(unref(cls).e("model-option-head")) }, [createElementVNode("span", { class: normalizeClass(unref(cls).e("model-option-name")) }, toDisplayString(item.label ?? item.id), 3), createElementVNode("span", { class: normalizeClass(unref(cls).e("model-option-actions")) }, [
101
+ item.reasoningLevels?.length ? (openBlock(), createElementBlock("button", {
102
+ key: 0,
103
+ type: "button",
104
+ class: normalizeClass([unref(cls).e("model-option-reasoning"), unref(bem).is("expanded", expandedReasoningId.value === item.id)]),
105
+ onClick: withModifiers(($event) => toggleReasoning(item), ["stop"])
106
+ }, [createElementVNode("span", null, toDisplayString(getReasoningLabel(item)), 1), createVNode(unref(UIcon), { class: normalizeClass(unref(cls).e("model-option-reasoning-arrow")) }, {
107
+ default: withCtx(() => [createVNode(unref(ArrowDown))]),
108
+ _: 1
109
+ }, 8, ["class"])], 10, _hoisted_2)) : createCommentVNode("v-if", true),
110
+ createCommentVNode(" 勾选槽位固定占位:未选中也保留位置,保证推理等级按钮跨行对齐 "),
111
+ createVNode(unref(UIcon), { class: normalizeClass([unref(cls).e("model-option-check"), unref(bem).is("hidden", item.id !== model.value)]) }, {
112
+ default: withCtx(() => [createVNode(unref(Check))]),
113
+ _: 1
114
+ }, 8, ["class"])
115
+ ], 2)], 2), item.description ? (openBlock(), createElementBlock("div", {
83
116
  key: 0,
84
117
  class: normalizeClass(unref(cls).e("model-option-desc"))
85
- }, toDisplayString(item.description), 3)) : createCommentVNode("v-if", true)], 10, _hoisted_1);
86
- }), 128)), reasoningLevels.value.length ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
87
- createElementVNode("div", { class: normalizeClass(unref(cls).e("model-divider")) }, null, 2),
88
- createElementVNode("div", {
89
- class: normalizeClass(unref(cls).e("reasoning-row")),
90
- onClick: toggleReasoning
91
- }, [_cache[0] || (_cache[0] = createElementVNode("span", null, "思考强度", -1)), createElementVNode("span", { class: normalizeClass(unref(cls).e("reasoning-row-value")) }, [createTextVNode(toDisplayString(currentReasoningLabel.value) + " ", 1), createVNode(unref(UIcon), null, {
92
- default: withCtx(() => [reasoningExpanded.value ? (openBlock(), createBlock(unref(ArrowDown), { key: 0 })) : (openBlock(), createBlock(unref(ArrowRight), { key: 1 }))]),
93
- _: 1
94
- })], 2)], 2),
95
- reasoningExpanded.value ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(reasoningLevels.value, (level) => {
118
+ }, toDisplayString(item.description), 3)) : createCommentVNode("v-if", true)], 10, _hoisted_1), item.reasoningLevels?.length ? (openBlock(), createElementBlock("div", {
119
+ key: 0,
120
+ class: normalizeClass([unref(cls).e("reasoning-levels"), unref(bem).is("expanded", expandedReasoningId.value === item.id)])
121
+ }, [createElementVNode("div", { class: normalizeClass(unref(cls).e("reasoning-levels-inner")) }, [(openBlock(true), createElementBlock(Fragment, null, renderList(item.reasoningLevels, (level) => {
96
122
  return openBlock(), createElementBlock("div", {
97
123
  key: level.value,
98
- class: normalizeClass([unref(cls).e("reasoning-option"), unref(bem).is("active", level.value === reasoningLevel.value)]),
99
- onClick: ($event) => handleSelectReasoning(level.value)
100
- }, [createElementVNode("span", null, toDisplayString(level.label), 1), level.value === reasoningLevel.value ? (openBlock(), createBlock(unref(UIcon), {
101
- key: 0,
102
- class: normalizeClass(unref(cls).e("model-option-check"))
103
- }, {
124
+ class: normalizeClass([unref(cls).e("reasoning-option"), unref(bem).is("active", isReasoningActive(item, level.value))]),
125
+ onClick: ($event) => handleSelectReasoning(item, level.value)
126
+ }, [createElementVNode("span", null, toDisplayString(level.label), 1), createVNode(unref(UIcon), { class: normalizeClass([unref(cls).e("model-option-check"), unref(bem).is("hidden", !isReasoningActive(item, level.value))]) }, {
104
127
  default: withCtx(() => [createVNode(unref(Check))]),
105
128
  _: 1
106
- }, 8, ["class"])) : createCommentVNode("v-if", true)], 10, _hoisted_2);
107
- }), 128)) : createCommentVNode("v-if", true)
108
- ], 64)) : createCommentVNode("v-if", true)]),
129
+ }, 8, ["class"])], 10, _hoisted_3);
130
+ }), 128))], 2)], 2)) : createCommentVNode("v-if", true)], 2);
131
+ }), 128))], 2)]),
109
132
  _: 1
110
133
  }, 8, ["content-class"]);
111
134
  };
@@ -1 +1 @@
1
- {"version":3,"file":"model-picker.js","names":[],"sources":["../../../src/components/ai-chat/model-picker.vue"],"sourcesContent":["<template>\n <UDropdown\n ref=\"dropdownRef\"\n trigger=\"click\"\n min-width=\"220px\"\n :content-class=\"cls.e('model-panel')\"\n >\n <template #trigger>\n <button type=\"button\" :class=\"cls.e('model-trigger')\">\n <span :class=\"cls.e('model-trigger-label')\">\n {{ currentModel?.label ?? model ?? '模型' }}\n </span>\n <span v-if=\"currentReasoningLabel\" :class=\"cls.e('model-trigger-reasoning')\">\n {{ currentReasoningLabel }}\n </span>\n <UIcon :class=\"cls.e('model-trigger-arrow')\">\n <ArrowDown />\n </UIcon>\n </button>\n </template>\n\n <template #content>\n <div\n v-for=\"item in models\"\n :key=\"item.id\"\n :class=\"[cls.e('model-option'), bem.is('active', item.id === model)]\"\n @click=\"handleSelectModel(item.id)\"\n >\n <div :class=\"cls.e('model-option-head')\">\n <span>{{ item.label ?? item.id }}</span>\n <UIcon v-if=\"item.id === model\" :class=\"cls.e('model-option-check')\">\n <Check />\n </UIcon>\n </div>\n <div v-if=\"item.description\" :class=\"cls.e('model-option-desc')\">\n {{ item.description }}\n </div>\n </div>\n\n <template v-if=\"reasoningLevels.length\">\n <div :class=\"cls.e('model-divider')\" />\n\n <div :class=\"cls.e('reasoning-row')\" @click=\"toggleReasoning\">\n <span>思考强度</span>\n <span :class=\"cls.e('reasoning-row-value')\">\n {{ currentReasoningLabel }}\n <UIcon>\n <ArrowDown v-if=\"reasoningExpanded\" />\n <ArrowRight v-else />\n </UIcon>\n </span>\n </div>\n\n <template v-if=\"reasoningExpanded\">\n <div\n v-for=\"level in reasoningLevels\"\n :key=\"level.value\"\n :class=\"[cls.e('reasoning-option'), bem.is('active', level.value === reasoningLevel)]\"\n @click=\"handleSelectReasoning(level.value)\"\n >\n <span>{{ level.label }}</span>\n <UIcon v-if=\"level.value === reasoningLevel\" :class=\"cls.e('model-option-check')\">\n <Check />\n </UIcon>\n </div>\n </template>\n </template>\n </template>\n </UDropdown>\n</template>\n\n<script lang=\"ts\" setup>\nimport { UDropdown, UIcon } from '@veltra/desktop'\nimport { ArrowDown, ArrowRight, Check } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, inject, nextTick, ref, useTemplateRef } from 'vue'\n\nimport type { ChatModelOption } from '../../providers'\nimport { AiChatDIKey } from './di'\n\ndefineOptions({ name: 'UAiChatModelPicker' })\n\nconst props = defineProps<{\n /** 可选模型列表 */\n models: ChatModelOption[]\n}>()\n\nconst model = defineModel<string>('model')\nconst reasoningLevel = defineModel<string>('reasoningLevel')\n\nconst di = inject(AiChatDIKey)\nconst cls = di?.cls ?? bem('ai-chat')\n\nconst dropdownRef = useTemplateRef('dropdownRef')\n\n/** 思考强度子列表是否展开 */\nconst reasoningExpanded = ref(false)\n\nconst currentModel = computed(() => {\n return props.models.find((m) => m.id === model.value)\n})\n\nconst reasoningLevels = computed(() => currentModel.value?.reasoningLevels ?? [])\n\nconst currentReasoningLabel = computed(() => {\n return reasoningLevels.value.find((l) => l.value === reasoningLevel.value)?.label\n})\n\n/** 展开/收起思考强度子列表,并重置面板位置防止溢出 */\nconst toggleReasoning = () => {\n reasoningExpanded.value = !reasoningExpanded.value\n nextTick(() => dropdownRef.value?.updateDropdown())\n}\n\n/** 选中模型(推理等级校正在 useChat 中完成) */\nconst handleSelectModel = (id: string) => {\n model.value = id\n reasoningExpanded.value = false\n dropdownRef.value?.close()\n}\n\nconst handleSelectReasoning = (value: string) => {\n reasoningLevel.value = value\n dropdownRef.value?.close()\n}\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;EAkFA,MAAM,QAAQ;EAKd,MAAM,QAAQ,SAAmB,SAAC,OAAO;EACzC,MAAM,iBAAiB,SAAmB,SAAC,gBAAgB;EAG3D,MAAM,MADK,OAAO,WACN,CAAA,EAAI,OAAO,IAAI,SAAS;EAEpC,MAAM,cAAc,eAAe,aAAa;;EAGhD,MAAM,oBAAoB,IAAI,KAAK;EAEnC,MAAM,eAAe,eAAe;GAClC,OAAO,MAAM,OAAO,MAAM,MAAM,EAAE,OAAO,MAAM,KAAK;EACtD,CAAC;EAED,MAAM,kBAAkB,eAAe,aAAa,OAAO,mBAAmB,CAAC,CAAC;EAEhF,MAAM,wBAAwB,eAAe;GAC3C,OAAO,gBAAgB,MAAM,MAAM,MAAM,EAAE,UAAU,eAAe,KAAK,CAAC,EAAE;EAC9E,CAAC;;EAGD,MAAM,wBAAwB;GAC5B,kBAAkB,QAAQ,CAAC,kBAAkB;GAC7C,eAAe,YAAY,OAAO,eAAe,CAAC;EACpD;;EAGA,MAAM,qBAAqB,OAAe;GACxC,MAAM,QAAQ;GACd,kBAAkB,QAAQ;GAC1B,YAAY,OAAO,MAAM;EAC3B;EAEA,MAAM,yBAAyB,UAAkB;GAC/C,eAAe,QAAQ;GACvB,YAAY,OAAO,MAAM;EAC3B;;GA3HE,OAAA,UAAA,GAAA,YAmEY,MAAA,SAAA,GAAA;IAlEN,SAAA;IAAJ,KAAI;IACJ,SAAQ;IACR,aAAU;IACT,iBAAe,MAAA,GAAA,CAAG,CAAC,EAAC,aAAA;;IAEV,SAAO,cAWP,CAVT,mBAUS,UAAA;KAVD,MAAK;KAAU,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,eAAA,CAAA;;KACjC,mBAEO,QAAA,EAFA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,qBAAA,CAAA,EAAA,GACd,gBAAA,aAAA,OAAc,SAAS,MAAA,SAAK,IAAA,GAAA,CAAA;KAErB,sBAAA,SAAA,UAAA,GAAZ,mBAEO,QAAA;;MAF6B,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,yBAAA,CAAA;KAC3C,GAAA,gBAAA,sBAAA,KAAqB,GAAA,CAAA,KAAA,mBAAA,QAAA,IAAA;KAE1B,YAEQ,MAAA,KAAA,GAAA,EAFA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,qBAAA,CAAA,EAAA,GAAA;MACL,SAAA,cAAA,CAAb,YAAa,MAAA,SAAA,CAAA,CAAA,CAAA;;;;IAKR,SAAO,cAEQ,EAAA,UAAA,IAAA,GADxB,mBAeM,UAAA,MAAA,WAdW,QAAA,SAAR,SAAI;KADb,OAAA,UAAA,GAAA,mBAeM,OAAA;MAbH,KAAK,KAAK;MACV,OAAK,eAAA,CAAG,MAAA,GAAA,CAAG,CAAC,EAAC,cAAA,GAAkB,MAAA,GAAA,CAAG,CAAC,GAAE,UAAW,KAAK,OAAO,MAAA,KAAK,CAAA,CAAA;MACjE,UAAK,WAAE,kBAAkB,KAAK,EAAE;KAEjC,GAAA,CAAA,mBAKM,OAAA,EALA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,mBAAA,CAAA,EAAA,GAChB,CAAA,mBAAwC,QAAA,MAAA,gBAA/B,KAAK,SAAS,KAAK,EAAE,GAAA,CAAA,GACjB,KAAK,OAAO,MAAA,SAAA,UAAA,GAAzB,YAEQ,MAAA,KAAA,GAAA;;MAFyB,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,oBAAA,CAAA;;MAClC,SAAA,cAAA,CAAT,YAAS,MAAA,KAAA,CAAA,CAAA,CAAA;;KAGF,GAAA,GAAA,CAAA,OAAA,CAAA,KAAA,mBAAA,QAAA,IAAA,CAAA,GAAA,CAAA,GAAA,KAAK,eAAA,UAAA,GAAhB,mBAEM,OAAA;;MAFwB,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,mBAAA,CAAA;KACrC,GAAA,gBAAA,KAAK,WAAW,GAAA,CAAA,KAAA,mBAAA,QAAA,IAAA,CAAA,GAAA,IAAA,UAAA;IAIP,CAAA,GAAA,GAAA,IAAA,gBAAA,MAAgB,UAAA,UAAA,GAAhC,mBA2BW,UAAA,EAAA,KAAA,EAAA,GAAA;KA1BT,mBAAuC,OAAA,EAAjC,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,eAAA,CAAA,EAAA,GAAA,MAAA,CAAA;KAElB,mBASM,OAAA;MATA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,eAAA,CAAA;MAAoB,SAAO;KAC3C,GAAA,CAAA,OAAA,OAAA,OAAA,KAAA,mBAAiB,QAAA,MAAX,QAAI,EAAA,IACV,mBAMO,QAAA,EANA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,qBAAA,CAAA,EAAA,GAAA,CAAA,gBACd,gBAAA,sBAAA,KAAqB,IAAG,KAC3B,CAAA,GAAA,YAGQ,MAAA,KAAA,GAAA,MAAA;MAFgC,SAAA,cAAA,CAArB,kBAAA,SAAA,UAAA,GAAjB,YAAsC,MAAA,SAAA,GAAA,EAAA,KAAA,EAAA,CAAA,MAAA,UAAA,GACtC,YAAqB,MAAA,UAAA,GAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA;;;KAKX,kBAAA,SAAA,UAAA,IAAA,GACd,mBAUM,UAAA,EAAA,KAAA,EAAA,GAAA,WATY,gBAAA,QAAT,UAAK;MADd,OAAA,UAAA,GAAA,mBAUM,OAAA;OARH,KAAK,MAAM;OACX,OAAK,eAAA,CAAG,MAAA,GAAA,CAAG,CAAC,EAAC,kBAAA,GAAsB,MAAA,GAAA,CAAG,CAAC,GAAE,UAAW,MAAM,UAAU,eAAA,KAAc,CAAA,CAAA;OAClF,UAAK,WAAE,sBAAsB,MAAM,KAAK;MAEzC,GAAA,CAAA,mBAA8B,QAAA,MAAA,gBAArB,MAAM,KAAK,GAAA,CAAA,GACP,MAAM,UAAU,eAAA,SAAA,UAAA,GAA7B,YAEQ,MAAA,KAAA,GAAA;;OAFsC,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,oBAAA,CAAA;;OAC/C,SAAA,cAAA,CAAT,YAAS,MAAA,KAAA,CAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"model-picker.js","names":[],"sources":["../../../src/components/ai-chat/model-picker.vue"],"sourcesContent":["<template>\n <UDropdown\n ref=\"dropdownRef\"\n trigger=\"click\"\n width=\"auto\"\n min-width=\"220px\"\n :content-class=\"cls.e('model-panel')\"\n @update:visible=\"handleVisibleChange\"\n >\n <template #trigger>\n <button type=\"button\" :class=\"cls.e('model-trigger')\">\n <span :class=\"cls.e('model-trigger-label')\">\n {{ currentModel?.label ?? model ?? '模型' }}\n </span>\n <span v-if=\"currentReasoningLabel\" :class=\"cls.e('model-trigger-reasoning')\">\n {{ currentReasoningLabel }}\n </span>\n <UIcon :class=\"cls.e('model-trigger-arrow')\">\n <ArrowDown />\n </UIcon>\n </button>\n </template>\n\n <template #content>\n <div :class=\"cls.e('model-panel-list')\">\n <div\n v-for=\"item in models\"\n :key=\"item.id\"\n :class=\"[cls.e('model-option'), bem.is('active', item.id === model)]\"\n >\n <div :class=\"cls.e('model-option-main')\" @click=\"handleSelectModel(item)\">\n <div :class=\"cls.e('model-option-head')\">\n <span :class=\"cls.e('model-option-name')\">{{ item.label ?? item.id }}</span>\n <span :class=\"cls.e('model-option-actions')\">\n <button\n v-if=\"item.reasoningLevels?.length\"\n type=\"button\"\n :class=\"[\n cls.e('model-option-reasoning'),\n bem.is('expanded', expandedReasoningId === item.id)\n ]\"\n @click.stop=\"toggleReasoning(item)\"\n >\n <span>{{ getReasoningLabel(item) }}</span>\n <UIcon :class=\"cls.e('model-option-reasoning-arrow')\">\n <ArrowDown />\n </UIcon>\n </button>\n <!-- 勾选槽位固定占位:未选中也保留位置,保证推理等级按钮跨行对齐 -->\n <UIcon :class=\"[cls.e('model-option-check'), bem.is('hidden', item.id !== model)]\">\n <Check />\n </UIcon>\n </span>\n </div>\n <div v-if=\"item.description\" :class=\"cls.e('model-option-desc')\">\n {{ item.description }}\n </div>\n </div>\n\n <div\n v-if=\"item.reasoningLevels?.length\"\n :class=\"[\n cls.e('reasoning-levels'),\n bem.is('expanded', expandedReasoningId === item.id)\n ]\"\n >\n <div :class=\"cls.e('reasoning-levels-inner')\">\n <div\n v-for=\"level in item.reasoningLevels\"\n :key=\"level.value\"\n :class=\"[\n cls.e('reasoning-option'),\n bem.is('active', isReasoningActive(item, level.value))\n ]\"\n @click=\"handleSelectReasoning(item, level.value)\"\n >\n <span>{{ level.label }}</span>\n <UIcon\n :class=\"[\n cls.e('model-option-check'),\n bem.is('hidden', !isReasoningActive(item, level.value))\n ]\"\n >\n <Check />\n </UIcon>\n </div>\n </div>\n </div>\n </div>\n </div>\n </template>\n </UDropdown>\n</template>\n\n<script lang=\"ts\" setup>\nimport { UDropdown, UIcon } from '@veltra/desktop'\nimport { ArrowDown, Check } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, inject, nextTick, shallowRef, useTemplateRef } from 'vue'\n\nimport type { ChatModelOption } from '../../providers'\nimport { AiChatDIKey } from './di'\n\ndefineOptions({ name: 'UAiChatModelPicker' })\n\nconst props = defineProps<{\n /** 可选模型列表 */\n models: ChatModelOption[]\n}>()\n\nconst model = defineModel<string | undefined>('model')\nconst reasoningLevel = defineModel<string | undefined>('reasoningLevel')\n\nconst di = inject(AiChatDIKey)\nconst cls = di?.cls ?? bem('ai-chat')\n\nconst dropdownRef = useTemplateRef('dropdownRef')\n\n/** 当前内联展开思考强度的模型 id(手风琴,同时只展开一个) */\nconst expandedReasoningId = shallowRef<string>()\n\nconst currentModel = computed(() => {\n return props.models.find((m) => m.id === model.value)\n})\n\nconst currentReasoningLabel = computed(() => {\n return currentModel.value?.reasoningLevels?.find((level) => level.value === reasoningLevel.value)\n ?.label\n})\n\n/** 取模型默认推理等级:显式配置优先,缺省落到首个可选等级 */\nconst resolveDefaultReasoningLevel = (item: ChatModelOption) => {\n const levels = item.reasoningLevels ?? []\n if (!levels.length) return undefined\n return (\n levels.find((level) => level.value === item.defaultReasoningLevel)?.value ?? levels[0]?.value\n )\n}\n\n/** 胶囊文案:已选中模型展示当前推理等级,其余展示该模型的默认等级 */\nconst getReasoningLabel = (item: ChatModelOption) => {\n if (item.id === model.value && currentReasoningLabel.value) {\n return currentReasoningLabel.value\n }\n return item.reasoningLevels?.find((level) => level.value === resolveDefaultReasoningLevel(item))\n ?.label\n}\n\nconst isReasoningActive = (item: ChatModelOption, value: string) => {\n return item.id === model.value && reasoningLevel.value === value\n}\n\n/** 关闭时收起内联思考强度,下次打开仍从模型列表开始 */\nconst handleVisibleChange = (visible: boolean) => {\n if (!visible) expandedReasoningId.value = undefined\n}\n\n/** 点击模型主体:直接选中模型,并同步到该模型默认推理等级 */\nconst handleSelectModel = (item: ChatModelOption) => {\n model.value = item.id\n reasoningLevel.value = resolveDefaultReasoningLevel(item)\n dropdownRef.value?.close()\n}\n\n/** 点击推理等级胶囊:内联展开/收起该模型的思考强度 */\nconst toggleReasoning = (item: ChatModelOption) => {\n expandedReasoningId.value = expandedReasoningId.value === item.id ? undefined : item.id\n nextTick(() => dropdownRef.value?.updateDropdown())\n}\n\n/** 选中思考强度:同时切到该等级所属模型,避免模型与推理等级错配 */\nconst handleSelectReasoning = (item: ChatModelOption, value: string) => {\n model.value = item.id\n reasoningLevel.value = value\n dropdownRef.value?.close()\n}\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAyGA,MAAM,QAAQ;EAKd,MAAM,QAAQ,SAA+B,SAAC,OAAO;EACrD,MAAM,iBAAiB,SAA+B,SAAC,gBAAgB;EAGvE,MAAM,MADK,OAAO,WACN,CAAA,EAAI,OAAO,IAAI,SAAS;EAEpC,MAAM,cAAc,eAAe,aAAa;;EAGhD,MAAM,sBAAsB,WAAmB;EAE/C,MAAM,eAAe,eAAe;GAClC,OAAO,MAAM,OAAO,MAAM,MAAM,EAAE,OAAO,MAAM,KAAK;EACtD,CAAC;EAED,MAAM,wBAAwB,eAAe;GAC3C,OAAO,aAAa,OAAO,iBAAiB,MAAM,UAAU,MAAM,UAAU,eAAe,KAAK,CAAA,EAC5F;EACN,CAAC;;EAGD,MAAM,gCAAgC,SAA0B;GAC9D,MAAM,SAAS,KAAK,mBAAmB,CAAC;GACxC,IAAI,CAAC,OAAO,QAAQ,OAAO,KAAA;GAC3B,OACE,OAAO,MAAM,UAAU,MAAM,UAAU,KAAK,qBAAqB,CAAC,EAAE,SAAS,OAAO,EAAE,EAAE;EAE5F;;EAGA,MAAM,qBAAqB,SAA0B;GACnD,IAAI,KAAK,OAAO,MAAM,SAAS,sBAAsB,OACnD,OAAO,sBAAsB;GAE/B,OAAO,KAAK,iBAAiB,MAAM,UAAU,MAAM,UAAU,6BAA6B,IAAI,CAAC,CAAA,EAC3F;EACN;EAEA,MAAM,qBAAqB,MAAuB,UAAkB;GAClE,OAAO,KAAK,OAAO,MAAM,SAAS,eAAe,UAAU;EAC7D;;EAGA,MAAM,uBAAuB,YAAqB;GAChD,IAAI,CAAC,SAAS,oBAAoB,QAAQ,KAAA;EAC5C;;EAGA,MAAM,qBAAqB,SAA0B;GACnD,MAAM,QAAQ,KAAK;GACnB,eAAe,QAAQ,6BAA6B,IAAI;GACxD,YAAY,OAAO,MAAM;EAC3B;;EAGA,MAAM,mBAAmB,SAA0B;GACjD,oBAAoB,QAAQ,oBAAoB,UAAU,KAAK,KAAK,KAAA,IAAY,KAAK;GACrF,eAAe,YAAY,OAAO,eAAe,CAAC;EACpD;;EAGA,MAAM,yBAAyB,MAAuB,UAAkB;GACtE,MAAM,QAAQ,KAAK;GACnB,eAAe,QAAQ;GACvB,YAAY,OAAO,MAAM;EAC3B;;GA9KE,OAAA,UAAA,GAAA,YA0FY,MAAA,SAAA,GAAA;IAzFN,SAAA;IAAJ,KAAI;IACJ,SAAQ;IACR,OAAM;IACN,aAAU;IACT,iBAAe,MAAA,GAAA,CAAG,CAAC,EAAC,aAAA;IACpB,oBAAgB;;IAEN,SAAO,cAWP,CAVT,mBAUS,UAAA;KAVD,MAAK;KAAU,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,eAAA,CAAA;;KACjC,mBAEO,QAAA,EAFA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,qBAAA,CAAA,EAAA,GACd,gBAAA,aAAA,OAAc,SAAS,MAAA,SAAK,IAAA,GAAA,CAAA;KAErB,sBAAA,SAAA,UAAA,GAAZ,mBAEO,QAAA;;MAF6B,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,yBAAA,CAAA;KAC3C,GAAA,gBAAA,sBAAA,KAAqB,GAAA,CAAA,KAAA,mBAAA,QAAA,IAAA;KAE1B,YAEQ,MAAA,KAAA,GAAA,EAFA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,qBAAA,CAAA,EAAA,GAAA;MACL,SAAA,cAAA,CAAb,YAAa,MAAA,SAAA,CAAA,CAAA,CAAA;;;;IAKR,SAAO,cAkEV,CAjEN,mBAiEM,OAAA,EAjEA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,kBAAA,CAAA,EAAA,GAChB,EAAA,UAAA,IAAA,GAAA,mBA+DM,UAAA,MAAA,WA9DW,QAAA,SAAR,SAAI;KADb,OAAA,UAAA,GAAA,mBA+DM,OAAA;MA7DH,KAAK,KAAK;MACV,OAAK,eAAA,CAAG,MAAA,GAAA,CAAG,CAAC,EAAC,cAAA,GAAkB,MAAA,GAAA,CAAG,CAAC,GAAE,UAAW,KAAK,OAAO,MAAA,KAAK,CAAA,CAAA;KAElE,GAAA,CAAA,mBA2BM,OAAA;MA3BA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,mBAAA,CAAA;MAAwB,UAAK,WAAE,kBAAkB,IAAI;KACrE,GAAA,CAAA,mBAsBM,OAAA,EAtBA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,mBAAA,CAAA,EAAA,GAChB,CAAA,mBAA4E,QAAA,EAArE,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,mBAAA,CAAA,EAAA,GAA0B,gBAAA,KAAK,SAAS,KAAK,EAAE,GAAA,CAAA,GAClE,mBAmBO,QAAA,EAnBA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,sBAAA,CAAA,EAAA,GAAA;MAET,KAAK,iBAAiB,UAAA,UAAA,GAD9B,mBAaS,UAAA;;OAXP,MAAK;OACJ,OAAK,eAAA,CAAwB,MAAA,GAAA,CAAG,CAAC,EAAC,wBAAA,GAAgD,MAAA,GAAA,CAAG,CAAC,GAAE,YAAa,oBAAA,UAAwB,KAAK,EAAE,CAAA,CAAA;OAIpI,SAAK,eAAA,WAAO,gBAAgB,IAAI,GAAA,CAAA,MAAA,CAAA;MAEjC,GAAA,CAAA,mBAA0C,QAAA,MAAA,gBAAjC,kBAAkB,IAAI,CAAA,GAAA,CAAA,GAC/B,YAEQ,MAAA,KAAA,GAAA,EAFA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,8BAAA,CAAA,EAAA,GAAA;OACL,SAAA,cAAA,CAAb,YAAa,MAAA,SAAA,CAAA,CAAA,CAAA;;;MAGjB,mBAAA,kCAAA;MACA,YAEQ,MAAA,KAAA,GAAA,EAFA,OAAK,eAAA,CAAG,MAAA,GAAA,CAAG,CAAC,EAAC,oBAAA,GAAwB,MAAA,GAAA,CAAG,CAAC,GAAE,UAAW,KAAK,OAAO,MAAA,KAAK,CAAA,CAAA,EAAA,GAAA;OACpE,SAAA,cAAA,CAAT,YAAS,MAAA,KAAA,CAAA,CAAA,CAAA;;;KAIJ,GAAA,CAAA,CAAA,GAAA,CAAA,GAAA,KAAK,eAAA,UAAA,GAAhB,mBAEM,OAAA;;MAFwB,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,mBAAA,CAAA;KACrC,GAAA,gBAAA,KAAK,WAAW,GAAA,CAAA,KAAA,mBAAA,QAAA,IAAA,CAAA,GAAA,IAAA,UAAA,GAKf,KAAK,iBAAiB,UAAA,UAAA,GAD9B,mBA4BM,OAAA;;MA1BH,OAAK,eAAA,CAAkB,MAAA,GAAA,CAAG,CAAC,EAAC,kBAAA,GAAoC,MAAA,GAAA,CAAG,CAAC,GAAE,YAAa,oBAAA,UAAwB,KAAK,EAAE,CAAA,CAAA;KAKnH,GAAA,CAAA,mBAoBM,OAAA,EApBA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,wBAAA,CAAA,EAAA,GAChB,EAAA,UAAA,IAAA,GAAA,mBAkBM,UAAA,MAAA,WAjBY,KAAK,kBAAd,UAAK;MADd,OAAA,UAAA,GAAA,mBAkBM,OAAA;OAhBH,KAAK,MAAM;OACX,OAAK,eAAA,CAAsB,MAAA,GAAA,CAAG,CAAC,EAAC,kBAAA,GAAwC,MAAA,GAAA,CAAG,CAAC,GAAE,UAAW,kBAAkB,MAAM,MAAM,KAAK,CAAA,CAAA,CAAA;OAI5H,UAAK,WAAE,sBAAsB,MAAM,MAAM,KAAK;MAE/C,GAAA,CAAA,mBAA8B,QAAA,MAAA,gBAArB,MAAM,KAAK,GAAA,CAAA,GACpB,YAOQ,MAAA,KAAA,GAAA,EANL,OAAK,eAAA,CAAwB,MAAA,GAAA,CAAG,CAAC,EAAC,oBAAA,GAA4C,MAAA,GAAA,CAAG,CAAC,GAAE,UAAA,CAAY,kBAAkB,MAAM,MAAM,KAAK,CAAA,CAAA,CAAA,EAAA,GAAA;OAK3H,SAAA,cAAA,CAAT,YAAS,MAAA,KAAA,CAAA,CAAA,CAAA"}
@@ -0,0 +1,70 @@
1
+ import { AiChatDIKey } from "./di.js";
2
+ import { Fragment, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, normalizeClass, openBlock, renderList, toDisplayString, unref, withCtx } from "vue";
3
+ import { CaretRight, Close, EditPen } from "@veltra/icons/normal";
4
+ import { UIcon } from "@veltra/desktop";
5
+ import { bem } from "@veltra/utils";
6
+ //#region src/components/ai-chat/queue-list.vue
7
+ const _hoisted_1 = ["title"];
8
+ const _hoisted_2 = ["onClick"];
9
+ const _hoisted_3 = ["onClick"];
10
+ const _hoisted_4 = ["onClick"];
11
+ const _sfc_main = /*@__PURE__*/ defineComponent({
12
+ name: "UAiChatQueueList",
13
+ __name: "queue-list",
14
+ props: { queue: {} },
15
+ emits: [
16
+ "start-now",
17
+ "edit",
18
+ "remove"
19
+ ],
20
+ setup(__props, { emit: __emit }) {
21
+ const emit = __emit;
22
+ const cls = inject(AiChatDIKey)?.cls ?? bem("ai-chat");
23
+ return (_ctx, _cache) => {
24
+ return __props.queue.length ? (openBlock(), createElementBlock("div", {
25
+ key: 0,
26
+ class: normalizeClass(unref(cls).e("queue"))
27
+ }, [createElementVNode("div", { class: normalizeClass(unref(cls).e("queue-head")) }, "待发送队列 · " + toDisplayString(__props.queue.length), 3), (openBlock(true), createElementBlock(Fragment, null, renderList(__props.queue, (item) => {
28
+ return openBlock(), createElementBlock("div", {
29
+ key: item.id,
30
+ class: normalizeClass(unref(cls).e("queue-item"))
31
+ }, [createElementVNode("span", {
32
+ class: normalizeClass(unref(cls).e("queue-text")),
33
+ title: item.content
34
+ }, toDisplayString(item.content), 11, _hoisted_1), createElementVNode("span", { class: normalizeClass(unref(cls).e("queue-actions")) }, [
35
+ createElementVNode("button", {
36
+ type: "button",
37
+ class: normalizeClass([unref(cls).e("queue-action"), unref(cls).em("queue-action", "primary")]),
38
+ title: "中断当前会话,立即执行该条",
39
+ onClick: ($event) => emit("start-now", item.id)
40
+ }, [createVNode(unref(UIcon), null, {
41
+ default: withCtx(() => [createVNode(unref(CaretRight))]),
42
+ _: 1
43
+ }), _cache[0] || (_cache[0] = createTextVNode("立即开始 ", -1))], 10, _hoisted_2),
44
+ createElementVNode("button", {
45
+ type: "button",
46
+ class: normalizeClass(unref(cls).e("queue-action")),
47
+ title: "取回输入框编辑",
48
+ onClick: ($event) => emit("edit", item.id)
49
+ }, [createVNode(unref(UIcon), null, {
50
+ default: withCtx(() => [createVNode(unref(EditPen))]),
51
+ _: 1
52
+ })], 10, _hoisted_3),
53
+ createElementVNode("button", {
54
+ type: "button",
55
+ class: normalizeClass(unref(cls).e("queue-action")),
56
+ title: "移出队列",
57
+ onClick: ($event) => emit("remove", item.id)
58
+ }, [createVNode(unref(UIcon), null, {
59
+ default: withCtx(() => [createVNode(unref(Close))]),
60
+ _: 1
61
+ })], 10, _hoisted_4)
62
+ ], 2)], 2);
63
+ }), 128))], 2)) : createCommentVNode("v-if", true);
64
+ };
65
+ }
66
+ });
67
+ //#endregion
68
+ export { _sfc_main as default };
69
+
70
+ //# sourceMappingURL=queue-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-list.js","names":[],"sources":["../../../src/components/ai-chat/queue-list.vue"],"sourcesContent":["<template>\n <div v-if=\"queue.length\" :class=\"cls.e('queue')\">\n <div :class=\"cls.e('queue-head')\">待发送队列 · {{ queue.length }}</div>\n <div v-for=\"item in queue\" :key=\"item.id\" :class=\"cls.e('queue-item')\">\n <span :class=\"cls.e('queue-text')\" :title=\"item.content\">{{ item.content }}</span>\n <span :class=\"cls.e('queue-actions')\">\n <button\n type=\"button\"\n :class=\"[cls.e('queue-action'), cls.em('queue-action', 'primary')]\"\n title=\"中断当前会话,立即执行该条\"\n @click=\"emit('start-now', item.id)\"\n >\n <UIcon><CaretRight /></UIcon>立即开始\n </button>\n <button\n type=\"button\"\n :class=\"cls.e('queue-action')\"\n title=\"取回输入框编辑\"\n @click=\"emit('edit', item.id)\"\n >\n <UIcon><EditPen /></UIcon>\n </button>\n <button\n type=\"button\"\n :class=\"cls.e('queue-action')\"\n title=\"移出队列\"\n @click=\"emit('remove', item.id)\"\n >\n <UIcon><Close /></UIcon>\n </button>\n </span>\n </div>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { UIcon } from '@veltra/desktop'\nimport { CaretRight, Close, EditPen } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { inject } from 'vue'\n\nimport type { ChatQueuedMessage } from '../../chat/types'\nimport { AiChatDIKey } from './di'\n\ndefineOptions({ name: 'UAiChatQueueList' })\n\ndefineProps<{\n /** 待发送队列(按执行顺序排列) */\n queue: ChatQueuedMessage[]\n}>()\n\nconst emit = defineEmits<{\n /** 立即开始:中断当前会话并插队执行 */\n (e: 'start-now', id: string): void\n /** 编辑:取回输入框重新编辑 */\n (e: 'edit', id: string): void\n /** 移出队列 */\n (e: 'remove', id: string): void\n}>()\n\nconst di = inject(AiChatDIKey)\nconst cls = di?.cls ?? bem('ai-chat')\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAmDA,MAAM,OAAO;EAUb,MAAM,MADK,OAAO,WACN,CAAA,EAAI,OAAO,IAAI,SAAS;;GA5DvB,OAAA,QAAA,MAAM,UAAA,UAAA,GAAjB,mBA+BM,OAAA;;IA/BoB,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,OAAA,CAAA;GACpC,GAAA,CAAA,mBAAkE,OAAA,EAA5D,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,YAAA,CAAA,EAAA,GAAgB,aAAQ,gBAAG,QAAA,MAAM,MAAM,GAAA,CAAA,IAAA,UAAA,IAAA,GACzD,mBA4BM,UAAA,MAAA,WA5Bc,QAAA,QAAR,SAAI;IAAhB,OAAA,UAAA,GAAA,mBA4BM,OAAA;KA5BsB,KAAK,KAAK;KAAK,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,YAAA,CAAA;IACrD,GAAA,CAAA,mBAAkF,QAAA;KAA3E,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,YAAA,CAAA;KAAiB,OAAO,KAAK;IAAY,GAAA,gBAAA,KAAK,OAAO,GAAA,IAAA,UAAA,GACxE,mBAyBO,QAAA,EAzBA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,eAAA,CAAA,EAAA,GAAA;KACjB,mBAOS,UAAA;MANP,MAAK;MACJ,OAAK,eAAA,CAAG,MAAA,GAAA,CAAG,CAAC,EAAC,cAAA,GAAkB,MAAA,GAAA,CAAG,CAAC,GAAE,gBAAA,SAAA,CAAA,CAAA;MACtC,OAAM;MACL,UAAK,WAAE,KAAI,aAAc,KAAK,EAAE;KAEjC,GAAA,CAAA,YAA6B,MAAA,KAAA,GAAA,MAAA;MAAR,SAAA,cAAA,CAAd,YAAc,MAAA,UAAA,CAAA,CAAA,CAAA;;KAAQ,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,gBAAA,SAC/B,EAAA,EAAA,GAAA,IAAA,UAAA;KACA,mBAOS,UAAA;MANP,MAAK;MACJ,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,cAAA,CAAA;MACb,OAAM;MACL,UAAK,WAAE,KAAI,QAAS,KAAK,EAAE;KAE5B,GAAA,CAAA,YAA0B,MAAA,KAAA,GAAA,MAAA;MAAR,SAAA,cAAA,CAAX,YAAW,MAAA,OAAA,CAAA,CAAA,CAAA;;;KAEpB,mBAOS,UAAA;MANP,MAAK;MACJ,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,cAAA,CAAA;MACb,OAAM;MACL,UAAK,WAAE,KAAI,UAAW,KAAK,EAAE;KAE9B,GAAA,CAAA,YAAwB,MAAA,KAAA,GAAA,MAAA;MAAR,SAAA,cAAA,CAAT,YAAS,MAAA,KAAA,CAAA,CAAA,CAAA"}
@@ -0,0 +1,96 @@
1
+ import { AiChatDIKey } from "./di.js";
2
+ import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, inject, normalizeClass, openBlock, resolveDynamicComponent, toDisplayString, unref, withCtx } from "vue";
3
+ import { CircleCheckFilled, CircleClose, Close, Loading, WarningFilled } from "@veltra/icons/normal";
4
+ import { UIcon, UScroll } from "@veltra/desktop";
5
+ import { bem } from "@veltra/utils";
6
+ //#region src/components/ai-chat/side-panel.vue
7
+ const _sfc_main = /*@__PURE__*/ defineComponent({
8
+ name: "UAiChatSidePanel",
9
+ __name: "side-panel",
10
+ props: { toolCall: {} },
11
+ emits: ["close"],
12
+ setup(__props, { emit: __emit }) {
13
+ const props = __props;
14
+ const emit = __emit;
15
+ const di = inject(AiChatDIKey);
16
+ const cls = di?.cls ?? bem("ai-chat");
17
+ /** 当前调用对应的工具定义(解析 icon/label/render) */
18
+ const tool = computed(() => di?.tools.value[props.toolCall.name]);
19
+ const STATUS_META = {
20
+ pending: {
21
+ icon: Loading,
22
+ class: "is-active"
23
+ },
24
+ running: {
25
+ icon: Loading,
26
+ class: "is-active"
27
+ },
28
+ "awaiting-confirm": {
29
+ icon: WarningFilled,
30
+ class: "is-warning"
31
+ },
32
+ success: {
33
+ icon: CircleCheckFilled,
34
+ class: "is-success"
35
+ },
36
+ error: {
37
+ icon: CircleClose,
38
+ class: "is-danger"
39
+ },
40
+ rejected: {
41
+ icon: Close,
42
+ class: "is-danger"
43
+ }
44
+ };
45
+ const statusIcon = computed(() => STATUS_META[props.toolCall.status]?.icon ?? Loading);
46
+ const statusClass = computed(() => STATUS_META[props.toolCall.status]?.class ?? "");
47
+ /** 头部图标:工具自定义图标优先,缺省用状态图标(与工具卡片一致) */
48
+ const headerIcon = computed(() => tool.value?.icon ?? statusIcon.value);
49
+ /** 面板标题:优先工具定义的 panelTitle(业务对象 + 动作),缺省回落到 label ?? name */
50
+ const panelTitle = computed(() => {
51
+ const t = tool.value;
52
+ const pt = t?.panelTitle;
53
+ if (typeof pt === "function") return pt(props.toolCall);
54
+ return pt ?? t?.label ?? props.toolCall.name;
55
+ });
56
+ /** 未提供 render 时的兜底展示(面板工具通常都应提供 render) */
57
+ const fallbackResult = computed(() => {
58
+ const raw = props.toolCall.error ?? props.toolCall.result ?? "";
59
+ try {
60
+ return JSON.stringify(JSON.parse(raw), null, 2);
61
+ } catch {
62
+ return raw;
63
+ }
64
+ });
65
+ return (_ctx, _cache) => {
66
+ return openBlock(), createElementBlock("aside", { class: normalizeClass(unref(cls).e("panel")) }, [createElementVNode("div", { class: normalizeClass(unref(cls).e("panel-card")) }, [createElementVNode("div", { class: normalizeClass(unref(cls).e("panel-header")) }, [
67
+ createVNode(unref(UIcon), { class: normalizeClass([unref(cls).e("panel-icon"), statusClass.value]) }, {
68
+ default: withCtx(() => [(openBlock(), createBlock(resolveDynamicComponent(headerIcon.value)))]),
69
+ _: 1
70
+ }, 8, ["class"]),
71
+ createElementVNode("span", { class: normalizeClass(unref(cls).e("panel-title")) }, toDisplayString(panelTitle.value), 3),
72
+ createVNode(unref(UIcon), {
73
+ class: normalizeClass(unref(cls).e("panel-close")),
74
+ title: "关闭面板",
75
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
76
+ }, {
77
+ default: withCtx(() => [createVNode(unref(Close))]),
78
+ _: 1
79
+ }, 8, ["class"])
80
+ ], 2), createVNode(unref(UScroll), { class: normalizeClass(unref(cls).e("panel-body")) }, {
81
+ default: withCtx(() => [createCommentVNode(" render 组件与工具卡片同一契约(ChatToolRenderProps),可随 toolCall 状态实时更新 "), tool.value?.render ? (openBlock(), createBlock(resolveDynamicComponent(tool.value.render), {
82
+ key: 0,
83
+ "tool-call": __props.toolCall
84
+ }, null, 8, ["tool-call"])) : (openBlock(), createElementBlock("pre", {
85
+ key: 1,
86
+ class: normalizeClass(unref(cls).e("panel-fallback"))
87
+ }, toDisplayString(fallbackResult.value), 3))]),
88
+ _: 1
89
+ }, 8, ["class"])], 2)], 2);
90
+ };
91
+ }
92
+ });
93
+ //#endregion
94
+ export { _sfc_main as default };
95
+
96
+ //# sourceMappingURL=side-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-panel.js","names":[],"sources":["../../../src/components/ai-chat/side-panel.vue"],"sourcesContent":["<template>\n <aside :class=\"cls.e('panel')\">\n <div :class=\"cls.e('panel-card')\">\n <div :class=\"cls.e('panel-header')\">\n <UIcon :class=\"[cls.e('panel-icon'), statusClass]\">\n <component :is=\"headerIcon\" />\n </UIcon>\n <span :class=\"cls.e('panel-title')\">{{ panelTitle }}</span>\n <UIcon :class=\"cls.e('panel-close')\" title=\"关闭面板\" @click=\"emit('close')\">\n <Close />\n </UIcon>\n </div>\n\n <UScroll :class=\"cls.e('panel-body')\">\n <!-- render 组件与工具卡片同一契约(ChatToolRenderProps),可随 toolCall 状态实时更新 -->\n <component :is=\"tool.render\" v-if=\"tool?.render\" :tool-call=\"toolCall\" />\n <pre v-else :class=\"cls.e('panel-fallback')\">{{ fallbackResult }}</pre>\n </UScroll>\n </div>\n </aside>\n</template>\n\n<script lang=\"ts\" setup>\nimport { UIcon, UScroll } from '@veltra/desktop'\nimport { CircleCheckFilled, CircleClose, Close, Loading, WarningFilled } from '@veltra/icons/normal'\nimport { bem } from '@veltra/utils'\nimport { computed, inject, type Component } from 'vue'\n\nimport type { ChatToolCall } from '../../chat/types'\nimport { AiChatDIKey } from './di'\n\ndefineOptions({ name: 'UAiChatSidePanel' })\n\nconst props = defineProps<{ toolCall: ChatToolCall }>()\n\nconst emit = defineEmits<{ (e: 'close'): void }>()\n\nconst di = inject(AiChatDIKey)\nconst cls = di?.cls ?? bem('ai-chat')\n\n/** 当前调用对应的工具定义(解析 icon/label/render) */\nconst tool = computed(() => di?.tools.value[props.toolCall.name])\n\nconst STATUS_META: Record<string, { icon: Component; class: string }> = {\n pending: { icon: Loading, class: 'is-active' },\n running: { icon: Loading, class: 'is-active' },\n 'awaiting-confirm': { icon: WarningFilled, class: 'is-warning' },\n success: { icon: CircleCheckFilled, class: 'is-success' },\n error: { icon: CircleClose, class: 'is-danger' },\n rejected: { icon: Close, class: 'is-danger' }\n}\n\nconst statusIcon = computed(() => STATUS_META[props.toolCall.status]?.icon ?? Loading)\nconst statusClass = computed(() => STATUS_META[props.toolCall.status]?.class ?? '')\n\n/** 头部图标:工具自定义图标优先,缺省用状态图标(与工具卡片一致) */\nconst headerIcon = computed(() => tool.value?.icon ?? statusIcon.value)\n\n/** 面板标题:优先工具定义的 panelTitle(业务对象 + 动作),缺省回落到 label ?? name */\nconst panelTitle = computed(() => {\n const t = tool.value\n const pt = t?.panelTitle\n if (typeof pt === 'function') return pt(props.toolCall)\n return pt ?? t?.label ?? props.toolCall.name\n})\n\n/** 未提供 render 时的兜底展示(面板工具通常都应提供 render) */\nconst fallbackResult = computed(() => {\n const raw = props.toolCall.error ?? props.toolCall.result ?? ''\n try {\n return JSON.stringify(JSON.parse(raw), null, 2)\n } catch {\n return raw\n }\n})\n</script>\n"],"mappings":";;;;;;;;;;;;EAiCA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAEb,MAAM,KAAK,OAAO,WAAW;EAC7B,MAAM,MAAM,IAAI,OAAO,IAAI,SAAS;;EAGpC,MAAM,OAAO,eAAe,IAAI,MAAM,MAAM,MAAM,SAAS,KAAK;EAEhE,MAAM,cAAkE;GACtE,SAAS;IAAE,MAAM;IAAS,OAAO;GAAY;GAC7C,SAAS;IAAE,MAAM;IAAS,OAAO;GAAY;GAC7C,oBAAoB;IAAE,MAAM;IAAe,OAAO;GAAa;GAC/D,SAAS;IAAE,MAAM;IAAmB,OAAO;GAAa;GACxD,OAAO;IAAE,MAAM;IAAa,OAAO;GAAY;GAC/C,UAAU;IAAE,MAAM;IAAO,OAAO;GAAY;EAC9C;EAEA,MAAM,aAAa,eAAe,YAAY,MAAM,SAAS,OAAO,EAAE,QAAQ,OAAO;EACrF,MAAM,cAAc,eAAe,YAAY,MAAM,SAAS,OAAO,EAAE,SAAS,EAAE;;EAGlF,MAAM,aAAa,eAAe,KAAK,OAAO,QAAQ,WAAW,KAAK;;EAGtE,MAAM,aAAa,eAAe;GAChC,MAAM,IAAI,KAAK;GACf,MAAM,KAAK,GAAG;GACd,IAAI,OAAO,OAAO,YAAY,OAAO,GAAG,MAAM,QAAQ;GACtD,OAAO,MAAM,GAAG,SAAS,MAAM,SAAS;EAC1C,CAAC;;EAGD,MAAM,iBAAiB,eAAe;GACpC,MAAM,MAAM,MAAM,SAAS,SAAS,MAAM,SAAS,UAAU;GAC7D,IAAI;IACF,OAAO,KAAK,UAAU,KAAK,MAAM,GAAG,GAAG,MAAM,CAAC;GAChD,QAAQ;IACN,OAAO;GACT;EACF,CAAC;;GAzEC,OAAA,UAAA,GAAA,mBAkBQ,SAAA,EAlBA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,OAAA,CAAA,EAAA,GAClB,CAAA,mBAgBM,OAAA,EAhBA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,YAAA,CAAA,EAAA,GAChB,CAAA,mBAQM,OAAA,EARA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,cAAA,CAAA,EAAA,GAAA;IAChB,YAEQ,MAAA,KAAA,GAAA,EAFA,OAAK,eAAA,CAAG,MAAA,GAAA,CAAG,CAAC,EAAC,YAAA,GAAgB,YAAA,KAAW,CAAA,EAAA,GAAA;KAChB,SAAA,cAAA,EAAA,UAAA,GAA9B,YAA8B,wBAAd,WAAA,KAAU,CAAA,EAAA,CAAA;;;IAE5B,mBAA2D,QAAA,EAApD,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,aAAA,CAAA,EAAA,GAAoB,gBAAA,WAAA,KAAU,GAAA,CAAA;IACjD,YAEQ,MAAA,KAAA,GAAA;KAFA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,aAAA,CAAA;KAAiB,OAAM;KAAQ,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,OAAA;;KACnD,SAAA,cAAA,CAAT,YAAS,MAAA,KAAA,CAAA,CAAA,CAAA;;;GAIb,GAAA,CAAA,GAAA,YAIU,MAAA,OAAA,GAAA,EAJA,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,YAAA,CAAA,EAAA,GAAA;IAC+C,SAAA,cAAA,CAAnE,mBAAA,8DAAA,GACmC,KAAA,OAAM,UAAA,UAAA,GAAzC,YAAyE,wBAAzD,KAAA,MAAK,MAAM,GAAA;;KAAuB,aAAW,QAAA;IAC7D,GAAA,MAAA,GAAA,CAAA,WAAA,CAAA,MAAA,UAAA,GAAA,mBAAuE,OAAA;;KAA1D,OAAK,eAAE,MAAA,GAAA,CAAG,CAAC,EAAC,gBAAA,CAAA;IAAuB,GAAA,gBAAA,eAAA,KAAc,GAAA,CAAA,EAAA,CAAA"}
@@ -1,7 +1,11 @@
1
1
  import "@veltra/desktop/components/button/style";
2
+ import "@veltra/desktop/components/collapse/style";
2
3
  import "@veltra/desktop/components/file-picker/style";
3
4
  import "@veltra/desktop/components/icon/style";
4
5
  import "@veltra/desktop/components/input/style";
6
+ import "@veltra/desktop/components/layout/style";
7
+ import "@veltra/desktop/components/message/style";
5
8
  import "@veltra/desktop/components/scroll/style";
6
9
  import "@veltra/desktop/components/select/style";
10
+ import "@veltra/styles/animations/shine.scss";
7
11
  import "markstream-vue/index.css";
@@ -1,8 +1,12 @@
1
1
  import "./style2.css";
2
2
  import "@veltra/desktop/components/button/style";
3
+ import "@veltra/desktop/components/collapse/style";
3
4
  import "@veltra/desktop/components/file-picker/style";
4
5
  import "@veltra/desktop/components/icon/style";
5
6
  import "@veltra/desktop/components/input/style";
7
+ import "@veltra/desktop/components/layout/style";
8
+ import "@veltra/desktop/components/message/style";
6
9
  import "@veltra/desktop/components/scroll/style";
7
10
  import "@veltra/desktop/components/select/style";
11
+ import "@veltra/styles/animations/shine.scss";
8
12
  import "markstream-vue/index.css";