docus 5.12.0 → 5.12.2
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/app/app.config.ts +7 -16
- package/app/components/app/AppHeaderBody.vue +14 -1
- package/app/components/app/AppHeaderCenter.vue +1 -1
- package/app/components/docs/DocsAsideLeftBody.vue +1 -0
- package/app/components/docs/DocsAsideMobileBar.vue +4 -4
- package/app/components/docs/DocsAsideRight.vue +1 -1
- package/app/composables/useSubNavigation.ts +1 -1
- package/app/composables/useUIConfig.ts +1 -1
- package/app/utils/assistantTools.ts +88 -0
- package/i18n/locales/ar.json +15 -1
- package/i18n/locales/be.json +15 -1
- package/i18n/locales/bg.json +15 -1
- package/i18n/locales/bn.json +15 -1
- package/i18n/locales/ca.json +15 -1
- package/i18n/locales/ckb.json +15 -1
- package/i18n/locales/cs.json +15 -1
- package/i18n/locales/da.json +15 -1
- package/i18n/locales/de.json +15 -1
- package/i18n/locales/el.json +15 -1
- package/i18n/locales/en.json +15 -1
- package/i18n/locales/es.json +15 -1
- package/i18n/locales/et.json +15 -1
- package/i18n/locales/fi.json +15 -1
- package/i18n/locales/fr.json +15 -1
- package/i18n/locales/he.json +15 -1
- package/i18n/locales/hi.json +15 -1
- package/i18n/locales/hy.json +15 -1
- package/i18n/locales/id.json +15 -1
- package/i18n/locales/it.json +15 -1
- package/i18n/locales/ja.json +15 -1
- package/i18n/locales/kk.json +15 -1
- package/i18n/locales/km.json +15 -1
- package/i18n/locales/ko.json +15 -1
- package/i18n/locales/ky.json +15 -1
- package/i18n/locales/lb.json +15 -1
- package/i18n/locales/ms.json +15 -1
- package/i18n/locales/nb.json +15 -1
- package/i18n/locales/nl.json +15 -1
- package/i18n/locales/pl.json +15 -1
- package/i18n/locales/pt-BR.json +15 -1
- package/i18n/locales/ro.json +15 -1
- package/i18n/locales/ru.json +15 -1
- package/i18n/locales/si.json +15 -1
- package/i18n/locales/sl.json +15 -1
- package/i18n/locales/sv.json +15 -1
- package/i18n/locales/tr.json +15 -1
- package/i18n/locales/uk.json +15 -1
- package/i18n/locales/ur.json +15 -1
- package/i18n/locales/vi.json +15 -1
- package/i18n/locales/zh-CN.json +15 -1
- package/modules/assistant/index.ts +5 -8
- package/modules/assistant/runtime/components/AssistantComark.ts +2 -1
- package/modules/assistant/runtime/components/AssistantFloatingInput.vue +13 -2
- package/modules/assistant/runtime/components/AssistantIndicator.vue +15 -6
- package/modules/assistant/runtime/components/AssistantPanel.vue +13 -42
- package/modules/assistant/runtime/server/api/search.ts +14 -16
- package/package.json +16 -33
package/i18n/locales/si.json
CHANGED
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
"close": "වසන්න",
|
|
44
44
|
"expand": "පුළුල් කරන්න",
|
|
45
45
|
"collapse": "හකුළන්න",
|
|
46
|
-
"thinking": "සිතමින්...",
|
|
47
46
|
"askMeAnything": "ඕන දෙයක් අහන්න",
|
|
48
47
|
"askMeAnythingDescription": "ලේඛන සැරිසැරීමට, සංකල්ප තේරුම් ගැනීමට සහ පිළිතුරු සෙවීමට උදවු ලබා ගන්න.",
|
|
49
48
|
"faq": "නිතර අසන පැන",
|
|
@@ -52,7 +51,22 @@
|
|
|
52
51
|
"explainWithAi": "AI සමඟ පැහැදිලි කරන්න",
|
|
53
52
|
"toolListPages": "ලැයිස්තුගත ලේඛන පිටු",
|
|
54
53
|
"toolReadPage": "කියවන්න",
|
|
54
|
+
"tools": {
|
|
55
|
+
"searching": "සොයමින්",
|
|
56
|
+
"searched": "සෙව්වා",
|
|
57
|
+
"reading": "කියවමින්",
|
|
58
|
+
"read": "කියෙව්වා",
|
|
59
|
+
"finding": "සොයමින්",
|
|
60
|
+
"found": "හමු විය",
|
|
61
|
+
"opening": "විවෘත කරමින්",
|
|
62
|
+
"opened": "විවෘත කළා",
|
|
63
|
+
"generating": "ජනනය කරමින්",
|
|
64
|
+
"generated": "ජනනය කළා",
|
|
65
|
+
"creating": "සාදමින්",
|
|
66
|
+
"created": "සෑදුවා"
|
|
67
|
+
},
|
|
55
68
|
"loading": {
|
|
69
|
+
"thinking": "සිතමින්...",
|
|
56
70
|
"searching": "ලේඛන සෙවීම",
|
|
57
71
|
"reading": "ලේඛන හරහා කියවීම",
|
|
58
72
|
"analyzing": "අන්තර්ගතය විශ්ලේෂණය කිරීම",
|
package/i18n/locales/sl.json
CHANGED
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
"close": "Zapri",
|
|
44
44
|
"expand": "Razširi",
|
|
45
45
|
"collapse": "Strni",
|
|
46
|
-
"thinking": "Razmišljanje...",
|
|
47
46
|
"askMeAnything": "Vprašaj karkoli",
|
|
48
47
|
"askMeAnythingDescription": "Poiščite pomoč pri krmarjenju po dokumentaciji, razumevanju konceptov in iskanju odgovorov.",
|
|
49
48
|
"faq": "Pogosta vprašanja",
|
|
@@ -52,7 +51,22 @@
|
|
|
52
51
|
"explainWithAi": "Razloži z AI",
|
|
53
52
|
"toolListPages": "Navedene strani dokumentacije",
|
|
54
53
|
"toolReadPage": "Preberi",
|
|
54
|
+
"tools": {
|
|
55
|
+
"searching": "Iskanje",
|
|
56
|
+
"searched": "Najdeno",
|
|
57
|
+
"reading": "Branje",
|
|
58
|
+
"read": "Prebrano",
|
|
59
|
+
"finding": "Iskanje",
|
|
60
|
+
"found": "Najdeno",
|
|
61
|
+
"opening": "Odpiranje",
|
|
62
|
+
"opened": "Odprto",
|
|
63
|
+
"generating": "Generiranje",
|
|
64
|
+
"generated": "Generirano",
|
|
65
|
+
"creating": "Ustvarjanje",
|
|
66
|
+
"created": "Ustvarjeno"
|
|
67
|
+
},
|
|
55
68
|
"loading": {
|
|
69
|
+
"thinking": "Razmišljanje...",
|
|
56
70
|
"searching": "Iskanje po dokumentaciji",
|
|
57
71
|
"reading": "Prebiranje dokumentov",
|
|
58
72
|
"analyzing": "Analiza vsebine",
|
package/i18n/locales/sv.json
CHANGED
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
"close": "Stäng",
|
|
44
44
|
"expand": "Expandera",
|
|
45
45
|
"collapse": "Kollapsa",
|
|
46
|
-
"thinking": "Funderar...",
|
|
47
46
|
"askMeAnything": "Fråga vad som helst",
|
|
48
47
|
"askMeAnythingDescription": "Få hjälp med att navigera i dokumentationen, förstå begrepp och hitta svar.",
|
|
49
48
|
"faq": "FAQ",
|
|
@@ -52,7 +51,22 @@
|
|
|
52
51
|
"explainWithAi": "Förklara med AI",
|
|
53
52
|
"toolListPages": "Listade dokumentationssidor",
|
|
54
53
|
"toolReadPage": "Läs",
|
|
54
|
+
"tools": {
|
|
55
|
+
"searching": "Söker",
|
|
56
|
+
"searched": "Sökt",
|
|
57
|
+
"reading": "Läser",
|
|
58
|
+
"read": "Läst",
|
|
59
|
+
"finding": "Söker",
|
|
60
|
+
"found": "Hittade",
|
|
61
|
+
"opening": "Öppnar",
|
|
62
|
+
"opened": "Öppnad",
|
|
63
|
+
"generating": "Genererar",
|
|
64
|
+
"generated": "Genererad",
|
|
65
|
+
"creating": "Skapar",
|
|
66
|
+
"created": "Skapad"
|
|
67
|
+
},
|
|
55
68
|
"loading": {
|
|
69
|
+
"thinking": "Funderar...",
|
|
56
70
|
"searching": "Söker i dokumentationen",
|
|
57
71
|
"reading": "Läser igenom dokumenten",
|
|
58
72
|
"analyzing": "Analysera innehållet",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
"close": "Kapat",
|
|
44
44
|
"expand": "Genişlet",
|
|
45
45
|
"collapse": "Daralt",
|
|
46
|
-
"thinking": "Düşünüyorum...",
|
|
47
46
|
"askMeAnything": "Her şeyi sor",
|
|
48
47
|
"askMeAnythingDescription": "Belgelerde gezinme, kavramları anlama ve yanıt bulma konusunda yardım alın.",
|
|
49
48
|
"faq": "SSS",
|
|
@@ -52,7 +51,22 @@
|
|
|
52
51
|
"explainWithAi": "Yapay zeka ile açıklayın",
|
|
53
52
|
"toolListPages": "Listelenen dokümantasyon sayfaları",
|
|
54
53
|
"toolReadPage": "Oku",
|
|
54
|
+
"tools": {
|
|
55
|
+
"searching": "Aranıyor",
|
|
56
|
+
"searched": "Arandı",
|
|
57
|
+
"reading": "Okunuyor",
|
|
58
|
+
"read": "Okundu",
|
|
59
|
+
"finding": "Aranıyor",
|
|
60
|
+
"found": "Bulundu",
|
|
61
|
+
"opening": "Açılıyor",
|
|
62
|
+
"opened": "Açıldı",
|
|
63
|
+
"generating": "Üretiliyor",
|
|
64
|
+
"generated": "Üretildi",
|
|
65
|
+
"creating": "Oluşturuluyor",
|
|
66
|
+
"created": "Oluşturuldu"
|
|
67
|
+
},
|
|
55
68
|
"loading": {
|
|
69
|
+
"thinking": "Düşünüyorum...",
|
|
56
70
|
"searching": "Dokümantasyonda arama",
|
|
57
71
|
"reading": "Dokümanlar okunuyor",
|
|
58
72
|
"analyzing": "İçerik analiz ediliyor",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
"close": "Закрити",
|
|
44
44
|
"expand": "Розгорнути",
|
|
45
45
|
"collapse": "Згорнути",
|
|
46
|
-
"thinking": "Думаючи...",
|
|
47
46
|
"askMeAnything": "Запитайте будь-що",
|
|
48
47
|
"askMeAnythingDescription": "Отримайте допомогу в навігації документацією, розумінні понять і пошуку відповідей.",
|
|
49
48
|
"faq": "Поширені запитання",
|
|
@@ -52,7 +51,22 @@
|
|
|
52
51
|
"explainWithAi": "Поясніть за допомогою ШІ",
|
|
53
52
|
"toolListPages": "Перелічені сторінки документації",
|
|
54
53
|
"toolReadPage": "Читати",
|
|
54
|
+
"tools": {
|
|
55
|
+
"searching": "Пошук",
|
|
56
|
+
"searched": "Знайдено",
|
|
57
|
+
"reading": "Читання",
|
|
58
|
+
"read": "Прочитано",
|
|
59
|
+
"finding": "Пошук",
|
|
60
|
+
"found": "Знайдено",
|
|
61
|
+
"opening": "Відкриття",
|
|
62
|
+
"opened": "Відкрито",
|
|
63
|
+
"generating": "Генерація",
|
|
64
|
+
"generated": "Згенеровано",
|
|
65
|
+
"creating": "Створення",
|
|
66
|
+
"created": "Створено"
|
|
67
|
+
},
|
|
55
68
|
"loading": {
|
|
69
|
+
"thinking": "Думаючи...",
|
|
56
70
|
"searching": "Пошук документації",
|
|
57
71
|
"reading": "Читання документів",
|
|
58
72
|
"analyzing": "Аналіз змісту",
|
package/i18n/locales/ur.json
CHANGED
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
"close": "بند",
|
|
44
44
|
"expand": "پھیلائیں۔",
|
|
45
45
|
"collapse": "سمٹنا",
|
|
46
|
-
"thinking": "سوچ رہا ہے...",
|
|
47
46
|
"askMeAnything": "کچھ بھی پوچھو",
|
|
48
47
|
"askMeAnythingDescription": "دستاویزات کو نیویگیٹ کرنے، تصورات کو سمجھنے اور جوابات تلاش کرنے میں مدد حاصل کریں۔",
|
|
49
48
|
"faq": "اکثر پوچھے گئے سوالات",
|
|
@@ -52,7 +51,22 @@
|
|
|
52
51
|
"explainWithAi": "AI کے ساتھ وضاحت کریں۔",
|
|
53
52
|
"toolListPages": "درج دستاویزات کے صفحات",
|
|
54
53
|
"toolReadPage": "پڑھیں",
|
|
54
|
+
"tools": {
|
|
55
|
+
"searching": "تلاش جاری",
|
|
56
|
+
"searched": "تلاش مکمل",
|
|
57
|
+
"reading": "پڑھ رہے ہیں",
|
|
58
|
+
"read": "پڑھا",
|
|
59
|
+
"finding": "تلاش جاری",
|
|
60
|
+
"found": "مل گیا",
|
|
61
|
+
"opening": "کھول رہے ہیں",
|
|
62
|
+
"opened": "کھولا",
|
|
63
|
+
"generating": "تیار کر رہے ہیں",
|
|
64
|
+
"generated": "تیار کیا",
|
|
65
|
+
"creating": "بنا رہے ہیں",
|
|
66
|
+
"created": "بنایا"
|
|
67
|
+
},
|
|
55
68
|
"loading": {
|
|
69
|
+
"thinking": "سوچ رہا ہے...",
|
|
56
70
|
"searching": "دستاویزات کی تلاش",
|
|
57
71
|
"reading": "دستاویزات کے ذریعے پڑھنا",
|
|
58
72
|
"analyzing": "مواد کا تجزیہ",
|
package/i18n/locales/vi.json
CHANGED
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
"close": "Đóng",
|
|
44
44
|
"expand": "Mở rộng",
|
|
45
45
|
"collapse": "Thu gọn",
|
|
46
|
-
"thinking": "Đang suy nghĩ...",
|
|
47
46
|
"askMeAnything": "Hỏi bất cứ điều gì",
|
|
48
47
|
"askMeAnythingDescription": "Nhận trợ giúp điều hướng tài liệu, hiểu các khái niệm và tìm câu trả lời.",
|
|
49
48
|
"faq": "Câu hỏi thường gặp",
|
|
@@ -52,7 +51,22 @@
|
|
|
52
51
|
"explainWithAi": "Giải thích bằng AI",
|
|
53
52
|
"toolListPages": "Các trang tài liệu được liệt kê",
|
|
54
53
|
"toolReadPage": "Đọc",
|
|
54
|
+
"tools": {
|
|
55
|
+
"searching": "Đang tìm",
|
|
56
|
+
"searched": "Đã tìm",
|
|
57
|
+
"reading": "Đang đọc",
|
|
58
|
+
"read": "Đã đọc",
|
|
59
|
+
"finding": "Đang tìm",
|
|
60
|
+
"found": "Đã tìm thấy",
|
|
61
|
+
"opening": "Đang mở",
|
|
62
|
+
"opened": "Đã mở",
|
|
63
|
+
"generating": "Đang tạo",
|
|
64
|
+
"generated": "Đã tạo",
|
|
65
|
+
"creating": "Đang tạo",
|
|
66
|
+
"created": "Đã tạo"
|
|
67
|
+
},
|
|
55
68
|
"loading": {
|
|
69
|
+
"thinking": "Đang suy nghĩ...",
|
|
56
70
|
"searching": "Tìm kiếm tài liệu",
|
|
57
71
|
"reading": "Đọc qua tài liệu",
|
|
58
72
|
"analyzing": "Phân tích nội dung",
|
package/i18n/locales/zh-CN.json
CHANGED
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
"close": "关闭",
|
|
44
44
|
"expand": "展开",
|
|
45
45
|
"collapse": "崩溃",
|
|
46
|
-
"thinking": "想着……",
|
|
47
46
|
"askMeAnything": "询问任何事情",
|
|
48
47
|
"askMeAnythingDescription": "获取浏览文档、理解概念和寻找答案的帮助。",
|
|
49
48
|
"faq": "常见问题解答",
|
|
@@ -52,7 +51,22 @@
|
|
|
52
51
|
"explainWithAi": "用AI解释",
|
|
53
52
|
"toolListPages": "列出的文档页面",
|
|
54
53
|
"toolReadPage": "阅读",
|
|
54
|
+
"tools": {
|
|
55
|
+
"searching": "搜索中",
|
|
56
|
+
"searched": "已搜索",
|
|
57
|
+
"reading": "读取中",
|
|
58
|
+
"read": "已读取",
|
|
59
|
+
"finding": "搜索中",
|
|
60
|
+
"found": "已找到",
|
|
61
|
+
"opening": "打开中",
|
|
62
|
+
"opened": "已打开",
|
|
63
|
+
"generating": "生成中",
|
|
64
|
+
"generated": "已生成",
|
|
65
|
+
"creating": "创建中",
|
|
66
|
+
"created": "已创建"
|
|
67
|
+
},
|
|
55
68
|
"loading": {
|
|
69
|
+
"thinking": "想着……",
|
|
56
70
|
"searching": "搜索文档",
|
|
57
71
|
"reading": "通读文档",
|
|
58
72
|
"analyzing": "分析内容",
|
|
@@ -33,9 +33,6 @@ export default defineNuxtModule<AssistantModuleOptions>({
|
|
|
33
33
|
meta: {
|
|
34
34
|
name: 'assistant',
|
|
35
35
|
},
|
|
36
|
-
moduleDependencies: {
|
|
37
|
-
'@comark/nuxt': {},
|
|
38
|
-
},
|
|
39
36
|
setup(_options, nuxt) {
|
|
40
37
|
const legacyOptions = nuxt.options.assistant
|
|
41
38
|
if (legacyOptions && Object.keys(legacyOptions).length > 0) {
|
|
@@ -77,6 +74,11 @@ export default defineNuxtModule<AssistantModuleOptions>({
|
|
|
77
74
|
}),
|
|
78
75
|
)
|
|
79
76
|
|
|
77
|
+
addComponent({
|
|
78
|
+
name: 'AssistantComark',
|
|
79
|
+
filePath: resolve('./runtime/components/AssistantComark'),
|
|
80
|
+
})
|
|
81
|
+
|
|
80
82
|
if (!hasAiGatewayAuth) {
|
|
81
83
|
nuxt.hook('modules:done', () => {
|
|
82
84
|
log.warn('AI assistant disabled: neither `AI_GATEWAY_API_KEY` nor `VERCEL_OIDC_TOKEN` found')
|
|
@@ -89,11 +91,6 @@ export default defineNuxtModule<AssistantModuleOptions>({
|
|
|
89
91
|
model: options.model,
|
|
90
92
|
}
|
|
91
93
|
|
|
92
|
-
addComponent({
|
|
93
|
-
name: 'AssistantComark',
|
|
94
|
-
filePath: resolve('./runtime/components/AssistantComark'),
|
|
95
|
-
})
|
|
96
|
-
|
|
97
94
|
const routePath = options.apiPath!.replace(/^\//, '')
|
|
98
95
|
addServerHandler({
|
|
99
96
|
route: `/${routePath}`,
|
|
@@ -49,6 +49,18 @@ defineShortcuts(shortcuts)
|
|
|
49
49
|
function onEscape() {
|
|
50
50
|
inputRef.value?.inputRef?.blur()
|
|
51
51
|
}
|
|
52
|
+
|
|
53
|
+
function onKeydown(event: KeyboardEvent) {
|
|
54
|
+
if (event.key === 'Enter' && !event.shiftKey && !event.altKey && !event.ctrlKey && !event.metaKey) {
|
|
55
|
+
event.preventDefault()
|
|
56
|
+
handleSubmit()
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (event.key === 'Escape') {
|
|
61
|
+
onEscape()
|
|
62
|
+
}
|
|
63
|
+
}
|
|
52
64
|
</script>
|
|
53
65
|
|
|
54
66
|
<template>
|
|
@@ -79,8 +91,7 @@ function onEscape() {
|
|
|
79
91
|
base: 'bg-default shadow-lg rounded-xl text-base',
|
|
80
92
|
trailing: 'pe-2',
|
|
81
93
|
}"
|
|
82
|
-
@keydown
|
|
83
|
-
@keydown.escape="onEscape"
|
|
94
|
+
@keydown="onKeydown"
|
|
84
95
|
>
|
|
85
96
|
<template #trailing>
|
|
86
97
|
<div class="flex items-center gap-2">
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { useDocusI18n } from '../../../../app/composables/useDocusI18n'
|
|
3
|
+
|
|
4
|
+
const { t } = useDocusI18n()
|
|
5
|
+
|
|
2
6
|
const size = 4
|
|
3
7
|
const dotSize = 2
|
|
4
8
|
const gap = 2
|
|
@@ -32,9 +36,14 @@ function nextStep() {
|
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
const statusMessages =
|
|
39
|
+
const statusMessages = computed(() => [
|
|
40
|
+
t('assistant.loading.thinking'),
|
|
41
|
+
t('assistant.loading.searching'),
|
|
42
|
+
t('assistant.loading.reading'),
|
|
43
|
+
t('assistant.loading.analyzing'),
|
|
44
|
+
])
|
|
36
45
|
const currentIndex = ref(0)
|
|
37
|
-
const displayedText = ref(statusMessages[0]!)
|
|
46
|
+
const displayedText = ref(statusMessages.value[0]!)
|
|
38
47
|
const chars = 'abcdefghijklmnopqrstuvwxyz'
|
|
39
48
|
|
|
40
49
|
function scramble(from: string, to: string) {
|
|
@@ -80,8 +89,8 @@ onMounted(() => {
|
|
|
80
89
|
matrixInterval = setInterval(nextStep, 120)
|
|
81
90
|
textInterval = setInterval(() => {
|
|
82
91
|
const prev = displayedText.value
|
|
83
|
-
currentIndex.value = (currentIndex.value + 1) % statusMessages.length
|
|
84
|
-
scramble(prev, statusMessages[currentIndex.value]!)
|
|
92
|
+
currentIndex.value = (currentIndex.value + 1) % statusMessages.value.length
|
|
93
|
+
scramble(prev, statusMessages.value[currentIndex.value]!)
|
|
85
94
|
}, 3500)
|
|
86
95
|
})
|
|
87
96
|
|
|
@@ -92,7 +101,7 @@ onUnmounted(() => {
|
|
|
92
101
|
</script>
|
|
93
102
|
|
|
94
103
|
<template>
|
|
95
|
-
<div class="flex items-center text-
|
|
104
|
+
<div class="flex items-center text-sm text-muted overflow-hidden">
|
|
96
105
|
<div
|
|
97
106
|
class="shrink-0 mr-2 grid"
|
|
98
107
|
:style="{
|
|
@@ -111,6 +120,6 @@ onUnmounted(() => {
|
|
|
111
120
|
/>
|
|
112
121
|
</div>
|
|
113
122
|
|
|
114
|
-
<UChatShimmer :text="displayedText"
|
|
123
|
+
<UChatShimmer :text="displayedText" />
|
|
115
124
|
</div>
|
|
116
125
|
</template>
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { ToolUIPart, DynamicToolUIPart } from 'ai'
|
|
3
|
-
import { DefaultChatTransport, isToolUIPart, isReasoningUIPart, isTextUIPart
|
|
3
|
+
import { DefaultChatTransport, isToolUIPart, isReasoningUIPart, isTextUIPart } from 'ai'
|
|
4
4
|
import { Chat } from '@ai-sdk/vue'
|
|
5
5
|
import { isPartStreaming, isToolStreaming } from '@nuxt/ui/utils/ai'
|
|
6
6
|
import { useDocusI18n } from '../../../../app/composables/useDocusI18n'
|
|
7
|
+
import { getToolText, getToolSuffix, getToolIcon } from '../../../../app/utils/assistantTools'
|
|
7
8
|
import AssistantComark from './AssistantComark'
|
|
8
9
|
import AssistantIndicator from './AssistantIndicator.vue'
|
|
9
10
|
|
|
@@ -71,54 +72,22 @@ watch(messages, (newMessages) => {
|
|
|
71
72
|
const canClear = computed(() => messages.value.length > 0)
|
|
72
73
|
|
|
73
74
|
type ToolPart = ToolUIPart | DynamicToolUIPart
|
|
74
|
-
type ToolState = ToolPart['state']
|
|
75
|
-
|
|
76
|
-
function getToolMessage(state: ToolState, toolName: string, input: Record<string, string | undefined>) {
|
|
77
|
-
const searchVerb = state === 'output-available' ? 'Searched' : 'Searching'
|
|
78
|
-
const readVerb = state === 'output-available' ? 'Read' : 'Reading'
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
'list-pages': `${searchVerb} pages`,
|
|
82
|
-
'get-page': `${readVerb} ${input.path || '...'}`,
|
|
83
|
-
}[toolName] || `${searchVerb} ${toolName}`
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function getToolText(part: ToolPart) {
|
|
87
|
-
return getToolMessage(part.state, getToolName(part), (part.input || {}) as Record<string, string | undefined>)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function getToolIcon(part: ToolPart): string {
|
|
91
|
-
const toolName = getToolName(part)
|
|
92
|
-
|
|
93
|
-
return {
|
|
94
|
-
'get-page': 'i-lucide-file-text',
|
|
95
|
-
}[toolName] || 'i-lucide-search'
|
|
96
|
-
}
|
|
97
75
|
|
|
98
76
|
function getToolOutput(part: ToolPart): string | undefined {
|
|
99
77
|
if (part.state !== 'output-available' || !part.output) return undefined
|
|
100
78
|
|
|
101
79
|
const output = part.output as Record<string, unknown>
|
|
80
|
+
const content = (output.content ?? output) as Array<{ text?: string }> | string
|
|
102
81
|
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
if (typeof content === 'string') return content
|
|
106
|
-
return content
|
|
107
|
-
?.map(c => c.text)
|
|
108
|
-
.filter(Boolean)
|
|
109
|
-
.join('\n') || undefined
|
|
82
|
+
if (typeof content === 'string') {
|
|
83
|
+
return content || undefined
|
|
110
84
|
}
|
|
111
85
|
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
if (typeof content === 'string') {
|
|
115
|
-
return content.length > 500 ? `${content.slice(0, 500)}…` : content
|
|
116
|
-
}
|
|
117
|
-
const text = content?.map(c => c.text).filter(Boolean).join('\n') || ''
|
|
118
|
-
return text.length > 500 ? `${text.slice(0, 500)}…` : text || undefined
|
|
86
|
+
if (Array.isArray(content)) {
|
|
87
|
+
return content.map(c => c.text).filter(Boolean).join('\n') || undefined
|
|
119
88
|
}
|
|
120
89
|
|
|
121
|
-
return JSON.stringify(output, null, 2)
|
|
90
|
+
return JSON.stringify(output, null, 2)
|
|
122
91
|
}
|
|
123
92
|
|
|
124
93
|
function onSubmit() {
|
|
@@ -214,7 +183,7 @@ defineShortcuts({
|
|
|
214
183
|
:status="chat.status"
|
|
215
184
|
compact
|
|
216
185
|
class="px-0 gap-2"
|
|
217
|
-
:user="{ ui: { container: 'max-w-full' } }"
|
|
186
|
+
:user="{ ui: { container: 'max-w-full pb-3' } }"
|
|
218
187
|
>
|
|
219
188
|
<template #indicator>
|
|
220
189
|
<AssistantIndicator />
|
|
@@ -230,6 +199,7 @@ defineShortcuts({
|
|
|
230
199
|
:text="part.text"
|
|
231
200
|
:streaming="isPartStreaming(part)"
|
|
232
201
|
icon="i-lucide-brain"
|
|
202
|
+
chevron="leading"
|
|
233
203
|
>
|
|
234
204
|
<AssistantComark
|
|
235
205
|
:markdown="part.text"
|
|
@@ -253,14 +223,15 @@ defineShortcuts({
|
|
|
253
223
|
|
|
254
224
|
<UChatTool
|
|
255
225
|
v-else-if="isToolUIPart(part)"
|
|
256
|
-
:text="getToolText(part)"
|
|
226
|
+
:text="getToolText(part, t)"
|
|
227
|
+
:suffix="getToolSuffix(part)"
|
|
257
228
|
:icon="getToolIcon(part)"
|
|
258
229
|
:streaming="isToolStreaming(part)"
|
|
259
230
|
chevron="leading"
|
|
260
231
|
>
|
|
261
232
|
<pre
|
|
262
233
|
v-if="getToolOutput(part)"
|
|
263
|
-
class="text-xs text-
|
|
234
|
+
class="text-xs text-muted whitespace-pre-wrap break-all rounded-md border border-muted bg-muted p-2 max-h-64 overflow-y-auto"
|
|
264
235
|
v-text="getToolOutput(part)"
|
|
265
236
|
/>
|
|
266
237
|
</UChatTool>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { streamText, convertToModelMessages } from 'ai'
|
|
1
|
+
import { streamText, convertToModelMessages, stepCountIs, smoothStream } from 'ai'
|
|
2
2
|
import type { ToolSet } from 'ai'
|
|
3
3
|
import { createMCPClient } from '@ai-sdk/mcp'
|
|
4
4
|
import type { H3Event } from 'h3'
|
|
@@ -22,19 +22,6 @@ function createLocalFetch(event: H3Event): typeof fetch {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
-
function stopWhenResponseComplete({ steps }: { steps: { text?: string, toolCalls?: unknown[] }[] }): boolean {
|
|
27
|
-
const lastStep = steps.at(-1)
|
|
28
|
-
if (!lastStep) return false
|
|
29
|
-
|
|
30
|
-
const hasText = Boolean(lastStep.text && lastStep.text.trim().length > 0)
|
|
31
|
-
const hasNoToolCalls = !lastStep.toolCalls || lastStep.toolCalls.length === 0
|
|
32
|
-
|
|
33
|
-
if (hasText && hasNoToolCalls) return true
|
|
34
|
-
|
|
35
|
-
return steps.length >= MAX_STEPS
|
|
36
|
-
}
|
|
37
|
-
|
|
38
25
|
function getSystemPrompt(siteName: string) {
|
|
39
26
|
return `You are the documentation assistant for ${siteName}. Help users navigate and understand the project documentation.
|
|
40
27
|
|
|
@@ -115,13 +102,24 @@ export default defineEventHandler(async (event) => {
|
|
|
115
102
|
|
|
116
103
|
return streamText({
|
|
117
104
|
model: config.assistant.model,
|
|
118
|
-
maxOutputTokens:
|
|
105
|
+
maxOutputTokens: 8000,
|
|
119
106
|
maxRetries: 2,
|
|
120
107
|
abortSignal: abortController.signal,
|
|
121
|
-
stopWhen:
|
|
108
|
+
stopWhen: stepCountIs(MAX_STEPS),
|
|
109
|
+
// On the last allowed step, disable tools so the model is forced to
|
|
110
|
+
// produce a final text answer instead of stopping mid tool-calling.
|
|
111
|
+
prepareStep: ({ stepNumber }) => {
|
|
112
|
+
return stepNumber >= MAX_STEPS - 1 ? { toolChoice: 'none' } : {}
|
|
113
|
+
},
|
|
114
|
+
providerOptions: {
|
|
115
|
+
gateway: {
|
|
116
|
+
caching: 'auto',
|
|
117
|
+
},
|
|
118
|
+
},
|
|
122
119
|
system: getSystemPrompt(siteName),
|
|
123
120
|
messages: await convertToModelMessages(messages),
|
|
124
121
|
tools: mcpTools as ToolSet,
|
|
122
|
+
experimental_transform: smoothStream(),
|
|
125
123
|
onFinish: closeMcp,
|
|
126
124
|
onAbort: closeMcp,
|
|
127
125
|
onError: closeMcp,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docus",
|
|
3
3
|
"description": "Nuxt layer for Docus documentation theme",
|
|
4
|
-
"version": "5.12.
|
|
4
|
+
"version": "5.12.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
7
7
|
"repository": {
|
|
@@ -23,63 +23,46 @@
|
|
|
23
23
|
"README.md"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@
|
|
27
|
-
"@
|
|
28
|
-
"@
|
|
26
|
+
"@ai-sdk/gateway": "^3.0.131",
|
|
27
|
+
"@ai-sdk/mcp": "^1.0.50",
|
|
28
|
+
"@ai-sdk/vue": "^3.0.205",
|
|
29
|
+
"@comark/vue": "^0.4.0",
|
|
30
|
+
"@iconify-json/lucide": "^1.2.112",
|
|
31
|
+
"@iconify-json/simple-icons": "^1.2.86",
|
|
32
|
+
"@iconify-json/vscode-icons": "^1.2.57",
|
|
29
33
|
"@nuxt/content": "^3.14.0",
|
|
30
34
|
"@nuxt/image": "^2.0.0",
|
|
31
|
-
"@nuxt/kit": "^4.4.
|
|
32
|
-
"@nuxt/ui": "^4.8.
|
|
35
|
+
"@nuxt/kit": "^4.4.8",
|
|
36
|
+
"@nuxt/ui": "^4.8.2",
|
|
33
37
|
"@nuxtjs/i18n": "^10.4.0",
|
|
34
38
|
"@nuxtjs/mcp-toolkit": "^0.17.2",
|
|
35
39
|
"@nuxtjs/mdc": "^0.22.0",
|
|
36
|
-
"@nuxtjs/robots": "^6.
|
|
40
|
+
"@nuxtjs/robots": "^6.1.1",
|
|
37
41
|
"@shikijs/core": "^4.2.0",
|
|
38
42
|
"@shikijs/engine-javascript": "^4.2.0",
|
|
39
43
|
"@shikijs/langs": "^4.2.0",
|
|
40
44
|
"@shikijs/stream": "^4.2.0",
|
|
41
45
|
"@shikijs/themes": "^4.2.0",
|
|
42
|
-
"@takumi-rs/core": "^1.
|
|
46
|
+
"@takumi-rs/core": "^1.8.5",
|
|
43
47
|
"@vueuse/core": "^14.3.0",
|
|
48
|
+
"ai": "^6.0.205",
|
|
44
49
|
"defu": "^6.1.7",
|
|
45
50
|
"exsolve": "^1.0.8",
|
|
46
51
|
"git-url-parse": "^16.1.0",
|
|
47
|
-
"motion-v": "^2.
|
|
52
|
+
"motion-v": "^2.3.0",
|
|
48
53
|
"nuxt-llms": "^0.2.0",
|
|
49
|
-
"nuxt-og-image": "
|
|
54
|
+
"nuxt-og-image": "~6.6.0",
|
|
50
55
|
"pathe": "^2.0.3",
|
|
51
56
|
"pkg-types": "^2.3.1",
|
|
52
57
|
"scule": "^1.3.0",
|
|
53
|
-
"tailwindcss": "^4.3.
|
|
58
|
+
"tailwindcss": "^4.3.1",
|
|
54
59
|
"ufo": "^1.6.4",
|
|
55
60
|
"yaml": "^2.9.0",
|
|
56
61
|
"zod": "^4.4.3",
|
|
57
62
|
"zod-to-json-schema": "^3.25.2"
|
|
58
63
|
},
|
|
59
64
|
"peerDependencies": {
|
|
60
|
-
"@ai-sdk/gateway": "^3.0.120",
|
|
61
|
-
"@ai-sdk/mcp": "^1.0.43",
|
|
62
|
-
"@ai-sdk/vue": "^3.0.191",
|
|
63
|
-
"@comark/nuxt": "^0.3.1",
|
|
64
|
-
"ai": "^6.0.191",
|
|
65
65
|
"better-sqlite3": "12.x",
|
|
66
66
|
"nuxt": "4.x"
|
|
67
|
-
},
|
|
68
|
-
"peerDependenciesMeta": {
|
|
69
|
-
"@ai-sdk/gateway": {
|
|
70
|
-
"optional": true
|
|
71
|
-
},
|
|
72
|
-
"@ai-sdk/mcp": {
|
|
73
|
-
"optional": true
|
|
74
|
-
},
|
|
75
|
-
"@ai-sdk/vue": {
|
|
76
|
-
"optional": true
|
|
77
|
-
},
|
|
78
|
-
"@comark/nuxt": {
|
|
79
|
-
"optional": true
|
|
80
|
-
},
|
|
81
|
-
"ai": {
|
|
82
|
-
"optional": true
|
|
83
|
-
}
|
|
84
67
|
}
|
|
85
68
|
}
|