@swiss-ai-hub/web 0.321.0 → 0.323.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/components/Event/Display/AddMemoryToChatHistoryEvent.vue +3 -3
- package/components/Event/Display/AttachedFileEvent.vue +42 -0
- package/components/Event/Display/AttachedFilesReadEvent.vue +22 -0
- package/components/Event/Display/BaseRetrieveMemoryEvent.vue +2 -2
- package/components/Event/Display/BaseStoreMemoryEvent.vue +2 -2
- package/components/Event/Display/CompleteConversationEvent.vue +35 -0
- package/components/Event/Display/ComposeContextEvent.vue +38 -0
- package/components/Event/Display/ContextComposedEvent.vue +60 -0
- package/components/Event/Display/ContextualizeConversationEvent.vue +26 -0
- package/components/Event/Display/ConversationContextualizedEvent.vue +34 -0
- package/components/Event/Display/HumanInTheLoopResponseEvent.vue +11 -1
- package/components/Event/Display/KnowledgeSearchedEvent.vue +33 -0
- package/components/Event/Display/MemoryRecalledEvent.vue +33 -0
- package/components/Event/Display/MemoryStorageRequestedEvent.vue +29 -0
- package/components/Event/Display/NotAMetaQuestionEvent.vue +20 -0
- package/components/Event/Display/Part/Facts.vue +39 -0
- package/components/Event/Display/Part/MessageList.vue +50 -0
- package/components/Event/Display/Part/ToolCalls.vue +58 -0
- package/components/Event/Display/Part/ToolLoopState.vue +36 -0
- package/components/Event/Display/ReadAttachedFilesEvent.vue +28 -0
- package/components/Event/Display/RecallMemoryEvent.vue +27 -0
- package/components/Event/Display/RunToolLoopEvent.vue +34 -0
- package/components/Event/Display/SandboxFileDisplayedEvent.vue +46 -0
- package/components/Event/Display/SearchKnowledgeEvent.vue +31 -0
- package/components/Event/Display/ToolCallApprovedEvent.vue +27 -0
- package/components/Event/Display/ToolCallsDecidedEvent.vue +24 -0
- package/components/Event/Display/ToolLoopCondensedEvent.vue +31 -0
- package/components/Event/Display/ToolLoopFinishedEvent.vue +49 -0
- package/components/Event/Display/ToolLoopIterationEvent.vue +18 -0
- package/components/Event/Display/ToolLoopStatusEvent.vue +27 -0
- package/components/Event/Display/ToolResultEvent.vue +38 -0
- package/components/Event/List/EventList.vue +1 -1
- package/components/FormKit/DynamicConfiguration.vue +6 -1
- package/components/FormKit/KnowledgeCollectionSelector.vue +281 -0
- package/components/FormKit/KnowledgeDatabaseSelector.vue +7 -0
- package/components/FormKit/LocaleInput.vue +2 -0
- package/components/FormKit/SecretFileInput.vue +181 -0
- package/components/FormKit/VectorStoreInput.vue +20 -1
- package/components/Knowledge/Database/CreateModal.vue +91 -2
- package/components/Knowledge/Database/SourceModal.vue +165 -0
- package/components/Knowledge/Document/UploadModal.vue +4 -0
- package/components/Knowledge/Namespace/Card.vue +4 -4
- package/components/Knowledge/Namespace/CreateModal.vue +1 -1
- package/components/Knowledge/Namespace/EditModal.vue +3 -4
- package/components/Role/AccessRulesEditor.vue +1 -1
- package/components/Service/Selection.vue +7 -1
- package/components/Support/IncidentButton.vue +37 -0
- package/components/Support/IncidentDialog.vue +119 -0
- package/components/User/Settings.vue +9 -8
- package/components/UserFiles/Browser.vue +361 -0
- package/components/UserFiles/MoveDialog.vue +77 -0
- package/components/UserFiles/NameDialog.vue +59 -0
- package/components/UserFiles/Preview.vue +110 -0
- package/composables/auth/useAuth.ts +19 -3
- package/composables/document/useDocumentIngestionPolling.ts +64 -0
- package/composables/document/useDocuments.ts +3 -0
- package/composables/document/useSourcePipelines.ts +23 -0
- package/composables/document/useUpdateDatabaseSource.ts +21 -0
- package/composables/event/useEventComponent.ts +46 -0
- package/composables/form/useFormKitTransform.ts +68 -17
- package/composables/openwebui/useOpenWebuiDisclaimer.ts +22 -0
- package/composables/suite/useApps.ts +12 -3
- package/composables/suite/useSuite.ts +2 -0
- package/composables/support/useIncidentAvailability.ts +17 -0
- package/composables/support/useIncidentContext.ts +56 -0
- package/composables/support/useIncidentForm.ts +45 -0
- package/composables/support/useIncidentReport.ts +16 -0
- package/composables/support/useOpenWebUIContext.ts +38 -0
- package/composables/tenant/useChatDisclaimer.ts +24 -0
- package/composables/user/useApplyLocale.ts +23 -0
- package/composables/user/useMyLocale.ts +20 -0
- package/composables/user/useRestorePreferredLocale.ts +38 -0
- package/composables/userFiles/useCreateUserFolder.ts +15 -0
- package/composables/userFiles/useDeleteUserFile.ts +15 -0
- package/composables/userFiles/useMoveUserFile.ts +15 -0
- package/composables/userFiles/useUploadUserFiles.ts +19 -0
- package/composables/userFiles/useUserFileContent.ts +24 -0
- package/composables/userFiles/useUserFiles.ts +25 -0
- package/formkit.config.ts +10 -2
- package/i18n/locales/de.yaml +171 -3
- package/i18n/locales/en.yaml +172 -3
- package/i18n/locales/fr.yaml +173 -3
- package/i18n/locales/it.yaml +173 -3
- package/layouts/default.vue +7 -1
- package/middleware/auth.global.ts +6 -3
- package/middleware/home-redirect.ts +15 -4
- package/package.json +4 -3
- package/pages/[tenant]/service/knowledge/[db]/[namespace].vue +6 -8
- package/pages/[tenant]/service/knowledge.vue +33 -7
- package/pages/[tenant]/service/openai/[thread_id]/[display_id]/files.vue +51 -0
- package/pages/[tenant]/service/openai.vue +61 -17
- package/pages/[tenant]/service/user-knowledge.vue +19 -0
- package/plugins/api-client.client.ts +5 -0
- package/plugins/oidc-client.ts +14 -7
- package/sdk/client/index.ts +171 -1
- package/sdk/client/schemas.gen.ts +18602 -8560
- package/sdk/client/sdk.gen.ts +482 -0
- package/sdk/client/types.gen.ts +13616 -7044
- package/types/EventFact.ts +4 -0
- package/utils/apiResponseGuard.ts +97 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<EventDisplayBase
|
|
3
|
+
:event="event"
|
|
4
|
+
:thread="thread"
|
|
5
|
+
icon="mdi:brain"
|
|
6
|
+
>
|
|
7
|
+
<EventDisplayPartFacts :facts="facts" />
|
|
8
|
+
</EventDisplayBase>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
import type { ContextualizedAgentEvent, RecallMemoryEvent, ThreadDto } from '@core/sdk/client'
|
|
13
|
+
import type { EventFact } from '@core/types/EventFact'
|
|
14
|
+
|
|
15
|
+
const props = defineProps<{
|
|
16
|
+
event: ContextualizedAgentEvent & { event: RecallMemoryEvent }
|
|
17
|
+
thread: ThreadDto
|
|
18
|
+
}>()
|
|
19
|
+
|
|
20
|
+
const { t } = useI18n()
|
|
21
|
+
|
|
22
|
+
const facts = computed<EventFact[]>(() => [
|
|
23
|
+
{ label: t('event.capability.query'), value: props.event.event.query },
|
|
24
|
+
{ label: t('event.capability.namespaces'), value: props.event.event.org_memory_namespaces ?? [] },
|
|
25
|
+
{ label: t('event.capability.toolCall'), value: props.event.event.tool_call_id },
|
|
26
|
+
])
|
|
27
|
+
</script>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<EventDisplayBase
|
|
3
|
+
:event="event"
|
|
4
|
+
:thread="thread"
|
|
5
|
+
icon="mynaui:tool"
|
|
6
|
+
>
|
|
7
|
+
<EventDisplayPartFacts :facts="facts" />
|
|
8
|
+
</EventDisplayBase>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
import type { ContextualizedAgentEvent, RunToolLoopEvent, ThreadDto } from '@core/sdk/client'
|
|
13
|
+
import type { EventFact } from '@core/types/EventFact'
|
|
14
|
+
|
|
15
|
+
const props = defineProps<{
|
|
16
|
+
event: ContextualizedAgentEvent & { event: RunToolLoopEvent }
|
|
17
|
+
thread: ThreadDto
|
|
18
|
+
}>()
|
|
19
|
+
|
|
20
|
+
const { t } = useI18n()
|
|
21
|
+
|
|
22
|
+
const facts = computed<EventFact[]>(() => [
|
|
23
|
+
{ label: t('event.toolLoop.loop'), value: props.event.event.loop },
|
|
24
|
+
{ label: t('event.toolLoop.mode'), value: t(`event.toolLoop.modes.${props.event.event.mode ?? 'answer'}`) },
|
|
25
|
+
{ label: t('event.toolLoop.narrowedTools'), value: props.event.event.tools ?? null },
|
|
26
|
+
{ label: t('event.toolLoop.maxIterations'), value: props.event.event.max_iterations },
|
|
27
|
+
{ label: t('event.capability.historyMessages'), value: (props.event.event.history ?? []).length },
|
|
28
|
+
{ label: t('event.capability.files'), value: (props.event.event.files ?? []).map(file => file.filename) },
|
|
29
|
+
{
|
|
30
|
+
label: t('event.capability.references'),
|
|
31
|
+
value: (props.event.event.knowledge_references ?? []).map(reference => `${reference.database} / ${reference.namespace}`),
|
|
32
|
+
},
|
|
33
|
+
])
|
|
34
|
+
</script>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<EventDisplayBase
|
|
3
|
+
:event="event"
|
|
4
|
+
:thread="thread"
|
|
5
|
+
icon="mdi:file-eye-outline"
|
|
6
|
+
>
|
|
7
|
+
<dl class="grid grid-cols-[max-content_1fr] gap-x-4 gap-y-1 text-sm">
|
|
8
|
+
<dt class="text-surface-500">
|
|
9
|
+
{{ t('event.sandboxFileDisplayed.file') }}
|
|
10
|
+
</dt>
|
|
11
|
+
<dd class="break-all font-medium">
|
|
12
|
+
{{ event.event.filename }}
|
|
13
|
+
</dd>
|
|
14
|
+
<dt class="text-surface-500">
|
|
15
|
+
{{ t('event.sandboxFileDisplayed.type') }}
|
|
16
|
+
</dt>
|
|
17
|
+
<dd>{{ event.event.content_type }}</dd>
|
|
18
|
+
<dt class="text-surface-500">
|
|
19
|
+
{{ t('event.sandboxFileDisplayed.size') }}
|
|
20
|
+
</dt>
|
|
21
|
+
<dd>{{ size }}</dd>
|
|
22
|
+
<dt class="text-surface-500">
|
|
23
|
+
{{ t('event.sandboxFileDisplayed.path') }}
|
|
24
|
+
</dt>
|
|
25
|
+
<dd class="break-all font-mono text-xs">
|
|
26
|
+
{{ event.event.path }}
|
|
27
|
+
</dd>
|
|
28
|
+
</dl>
|
|
29
|
+
</EventDisplayBase>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script setup lang="ts">
|
|
33
|
+
import type { SandboxFileDisplayedEvent, ThreadDto, ContextualizedAgentEvent } from '@core/sdk/client'
|
|
34
|
+
|
|
35
|
+
const props = defineProps<{
|
|
36
|
+
event: ContextualizedAgentEvent & { event: SandboxFileDisplayedEvent }
|
|
37
|
+
thread: ThreadDto
|
|
38
|
+
}>()
|
|
39
|
+
|
|
40
|
+
const { t, n } = useI18n()
|
|
41
|
+
|
|
42
|
+
const size = computed<string>(() => {
|
|
43
|
+
const bytes = props.event.event.size
|
|
44
|
+
return bytes < 1024 ? `${bytes} B` : `${n(Math.round(bytes / 102.4) / 10)} KB`
|
|
45
|
+
})
|
|
46
|
+
</script>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<EventDisplayBase
|
|
3
|
+
:event="event"
|
|
4
|
+
:thread="thread"
|
|
5
|
+
icon="mage:search"
|
|
6
|
+
>
|
|
7
|
+
<EventDisplayPartFacts :facts="facts" />
|
|
8
|
+
</EventDisplayBase>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
import type { ContextualizedAgentEvent, SearchKnowledgeEvent, ThreadDto } from '@core/sdk/client'
|
|
13
|
+
import type { EventFact } from '@core/types/EventFact'
|
|
14
|
+
|
|
15
|
+
const props = defineProps<{
|
|
16
|
+
event: ContextualizedAgentEvent & { event: SearchKnowledgeEvent }
|
|
17
|
+
thread: ThreadDto
|
|
18
|
+
}>()
|
|
19
|
+
|
|
20
|
+
const { t } = useI18n()
|
|
21
|
+
|
|
22
|
+
const facts = computed<EventFact[]>(() => [
|
|
23
|
+
{ label: t('event.capability.query'), value: props.event.event.query },
|
|
24
|
+
{
|
|
25
|
+
label: t('event.capability.references'),
|
|
26
|
+
value: (props.event.event.references ?? []).map(reference => `${reference.database} / ${reference.namespace}`),
|
|
27
|
+
},
|
|
28
|
+
{ label: t('event.capability.citeSources'), value: t(props.event.event.cite_sources ? 'event.parts.yes' : 'event.parts.no') },
|
|
29
|
+
{ label: t('event.capability.toolCall'), value: props.event.event.tool_call_id },
|
|
30
|
+
])
|
|
31
|
+
</script>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<EventDisplayBase
|
|
3
|
+
:event="event"
|
|
4
|
+
:thread="thread"
|
|
5
|
+
icon="mynaui:tool"
|
|
6
|
+
>
|
|
7
|
+
<EventDisplayPartFacts :facts="facts" />
|
|
8
|
+
</EventDisplayBase>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
import type { ContextualizedAgentEvent, ThreadDto, ToolCallApprovedEvent } from '@core/sdk/client'
|
|
13
|
+
import type { EventFact } from '@core/types/EventFact'
|
|
14
|
+
|
|
15
|
+
const props = defineProps<{
|
|
16
|
+
event: ContextualizedAgentEvent & { event: ToolCallApprovedEvent }
|
|
17
|
+
thread: ThreadDto
|
|
18
|
+
}>()
|
|
19
|
+
|
|
20
|
+
const { t } = useI18n()
|
|
21
|
+
|
|
22
|
+
const facts = computed<EventFact[]>(() => [
|
|
23
|
+
{ label: t('event.toolLoop.tool'), value: props.event.event.name },
|
|
24
|
+
{ label: t('event.toolLoop.kind'), value: t(`event.toolLoop.kinds.${props.event.event.kind}`) },
|
|
25
|
+
{ label: t('event.capability.toolCall'), value: props.event.event.tool_call_id },
|
|
26
|
+
])
|
|
27
|
+
</script>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<EventDisplayBase
|
|
3
|
+
:event="event"
|
|
4
|
+
:thread="thread"
|
|
5
|
+
icon="mynaui:tool"
|
|
6
|
+
>
|
|
7
|
+
<div class="flex flex-col gap-6">
|
|
8
|
+
<EventDisplayPartToolCalls
|
|
9
|
+
:messages="event.event.state.messages"
|
|
10
|
+
:tool-call-ids="event.event.tool_call_ids"
|
|
11
|
+
/>
|
|
12
|
+
<EventDisplayPartToolLoopState :state="event.event.state" />
|
|
13
|
+
</div>
|
|
14
|
+
</EventDisplayBase>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script setup lang="ts">
|
|
18
|
+
import type { ContextualizedAgentEvent, ThreadDto, ToolCallsDecidedEvent } from '@core/sdk/client'
|
|
19
|
+
|
|
20
|
+
defineProps<{
|
|
21
|
+
event: ContextualizedAgentEvent & { event: ToolCallsDecidedEvent }
|
|
22
|
+
thread: ThreadDto
|
|
23
|
+
}>()
|
|
24
|
+
</script>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<EventDisplayBase
|
|
3
|
+
:event="event"
|
|
4
|
+
:thread="thread"
|
|
5
|
+
icon="lucide:layers"
|
|
6
|
+
>
|
|
7
|
+
<EventDisplayPartFacts :facts="facts" />
|
|
8
|
+
</EventDisplayBase>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
import type { ContextualizedAgentEvent, ThreadDto, ToolLoopCondensedEvent } from '@core/sdk/client'
|
|
13
|
+
import type { EventFact } from '@core/types/EventFact'
|
|
14
|
+
|
|
15
|
+
const props = defineProps<{
|
|
16
|
+
event: ContextualizedAgentEvent & { event: ToolLoopCondensedEvent }
|
|
17
|
+
thread: ThreadDto
|
|
18
|
+
}>()
|
|
19
|
+
|
|
20
|
+
const { t } = useI18n()
|
|
21
|
+
|
|
22
|
+
const facts = computed<EventFact[]>(() => [
|
|
23
|
+
{ label: t('event.toolLoop.loop'), value: props.event.event.loop },
|
|
24
|
+
{
|
|
25
|
+
label: t('event.toolLoop.tokens'),
|
|
26
|
+
value: `${props.event.event.tokens_before} → ${props.event.event.tokens_after}`,
|
|
27
|
+
},
|
|
28
|
+
{ label: t('event.toolLoop.condensedResults'), value: props.event.event.condensed_results ?? 0 },
|
|
29
|
+
{ label: t('event.toolLoop.condensedTurns'), value: props.event.event.condensed_turns ?? 0 },
|
|
30
|
+
])
|
|
31
|
+
</script>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<EventDisplayBase
|
|
3
|
+
:event="event"
|
|
4
|
+
:thread="thread"
|
|
5
|
+
icon="mynaui:tool"
|
|
6
|
+
>
|
|
7
|
+
<div class="flex flex-col gap-4">
|
|
8
|
+
<EventDisplayPartFacts :facts="facts" />
|
|
9
|
+
<Tag
|
|
10
|
+
v-if="event.event.stopped_early"
|
|
11
|
+
:value="t('event.toolLoop.stoppedEarly')"
|
|
12
|
+
severity="warn"
|
|
13
|
+
class="self-start"
|
|
14
|
+
/>
|
|
15
|
+
<p
|
|
16
|
+
v-if="answer"
|
|
17
|
+
class="whitespace-pre-wrap rounded-xl bg-surface-50 p-3 text-sm dark:bg-surface-850"
|
|
18
|
+
>
|
|
19
|
+
{{ answer }}
|
|
20
|
+
</p>
|
|
21
|
+
<EventDisplayPartMessageList
|
|
22
|
+
v-if="(event.event.block ?? []).length > 0"
|
|
23
|
+
:messages="event.event.block ?? []"
|
|
24
|
+
:event="event"
|
|
25
|
+
:thread="thread"
|
|
26
|
+
:title="t('event.toolLoop.gathered')"
|
|
27
|
+
/>
|
|
28
|
+
</div>
|
|
29
|
+
</EventDisplayBase>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script setup lang="ts">
|
|
33
|
+
import type { ContextualizedAgentEvent, ThreadDto, ToolLoopFinishedEvent } from '@core/sdk/client'
|
|
34
|
+
import type { EventFact } from '@core/types/EventFact'
|
|
35
|
+
|
|
36
|
+
const props = defineProps<{
|
|
37
|
+
event: ContextualizedAgentEvent & { event: ToolLoopFinishedEvent }
|
|
38
|
+
thread: ThreadDto
|
|
39
|
+
}>()
|
|
40
|
+
|
|
41
|
+
const { t } = useI18n()
|
|
42
|
+
|
|
43
|
+
const answer = computed(() => props.event.event.answer?.output_messages?.at(-1)?.content)
|
|
44
|
+
|
|
45
|
+
const facts = computed<EventFact[]>(() => [
|
|
46
|
+
{ label: t('event.toolLoop.loop'), value: props.event.event.loop },
|
|
47
|
+
{ label: t('event.toolLoop.gatheredMessages'), value: (props.event.event.block ?? []).length || null },
|
|
48
|
+
])
|
|
49
|
+
</script>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<EventDisplayBase
|
|
3
|
+
:event="event"
|
|
4
|
+
:thread="thread"
|
|
5
|
+
icon="mynaui:tool"
|
|
6
|
+
>
|
|
7
|
+
<EventDisplayPartToolLoopState :state="event.event.state" />
|
|
8
|
+
</EventDisplayBase>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup lang="ts">
|
|
12
|
+
import type { ContextualizedAgentEvent, ThreadDto, ToolLoopIterationEvent } from '@core/sdk/client'
|
|
13
|
+
|
|
14
|
+
defineProps<{
|
|
15
|
+
event: ContextualizedAgentEvent & { event: ToolLoopIterationEvent }
|
|
16
|
+
thread: ThreadDto
|
|
17
|
+
}>()
|
|
18
|
+
</script>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<EventDisplayBase
|
|
3
|
+
:event="event"
|
|
4
|
+
:thread="thread"
|
|
5
|
+
icon="mynaui:tool"
|
|
6
|
+
>
|
|
7
|
+
<div class="flex items-center gap-2 text-sm">
|
|
8
|
+
<Icon
|
|
9
|
+
:name="event.event.done ? 'mage:check-circle' : 'mage:loading'"
|
|
10
|
+
class="size-4"
|
|
11
|
+
/>
|
|
12
|
+
<span>{{ event.event.description }}</span>
|
|
13
|
+
<span class="text-xs text-surface-500 dark:text-surface-400">{{ t('event.toolLoop.loop') }}: {{ event.event.loop }}</span>
|
|
14
|
+
</div>
|
|
15
|
+
</EventDisplayBase>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script setup lang="ts">
|
|
19
|
+
import type { ContextualizedAgentEvent, ThreadDto, ToolLoopStatusEvent } from '@core/sdk/client'
|
|
20
|
+
|
|
21
|
+
defineProps<{
|
|
22
|
+
event: ContextualizedAgentEvent & { event: ToolLoopStatusEvent }
|
|
23
|
+
thread: ThreadDto
|
|
24
|
+
}>()
|
|
25
|
+
|
|
26
|
+
const { t } = useI18n()
|
|
27
|
+
</script>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<EventDisplayBase
|
|
3
|
+
:event="event"
|
|
4
|
+
:thread="thread"
|
|
5
|
+
icon="mynaui:tool"
|
|
6
|
+
>
|
|
7
|
+
<div class="flex flex-col gap-4">
|
|
8
|
+
<div class="flex items-center gap-2">
|
|
9
|
+
<span class="font-semibold">{{ event.event.name }}</span>
|
|
10
|
+
<Tag
|
|
11
|
+
v-if="event.event.is_error"
|
|
12
|
+
:value="t('event.toolLoop.failed')"
|
|
13
|
+
severity="danger"
|
|
14
|
+
/>
|
|
15
|
+
<span class="text-xs text-surface-500 dark:text-surface-400">{{ event.event.tool_call_id }}</span>
|
|
16
|
+
</div>
|
|
17
|
+
<pre class="max-h-96 overflow-auto whitespace-pre-wrap break-words rounded-xl bg-surface-50 p-3 text-xs dark:bg-surface-850">{{ event.event.content }}</pre>
|
|
18
|
+
<EventDisplayPartMessageList
|
|
19
|
+
v-if="(event.event.block ?? []).length > 0"
|
|
20
|
+
:messages="event.event.block ?? []"
|
|
21
|
+
:event="event"
|
|
22
|
+
:thread="thread"
|
|
23
|
+
:title="t('event.toolLoop.resultContext')"
|
|
24
|
+
/>
|
|
25
|
+
</div>
|
|
26
|
+
</EventDisplayBase>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
import type { ContextualizedAgentEvent, ThreadDto, ToolResultEvent } from '@core/sdk/client'
|
|
31
|
+
|
|
32
|
+
defineProps<{
|
|
33
|
+
event: ContextualizedAgentEvent & { event: ToolResultEvent }
|
|
34
|
+
thread: ThreadDto
|
|
35
|
+
}>()
|
|
36
|
+
|
|
37
|
+
const { t } = useI18n()
|
|
38
|
+
</script>
|
|
@@ -144,7 +144,7 @@ const { resolveComponentForEvent } = useEventComponent()
|
|
|
144
144
|
|
|
145
145
|
const runNameFn = (run: RunStatistics) => run.agent.agent_config.name
|
|
146
146
|
|
|
147
|
-
const getEventTimestamp = (event:
|
|
147
|
+
const getEventTimestamp = (event: ContextualizedAgentEvent): number =>
|
|
148
148
|
(event.event as { created_at?: number }).created_at ?? 0
|
|
149
149
|
|
|
150
150
|
const sortedEvents = computed(() =>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
id="form"
|
|
5
5
|
v-model="data"
|
|
6
6
|
type="form"
|
|
7
|
-
:submit-label="t('common.actions.save')"
|
|
7
|
+
:submit-label="props.submitLabel ?? t('common.actions.save')"
|
|
8
8
|
:submit-attrs="{
|
|
9
9
|
inputClass: 'p-button p-component w-full',
|
|
10
10
|
}"
|
|
@@ -32,6 +32,9 @@
|
|
|
32
32
|
:max="rep.max"
|
|
33
33
|
@update:model-value="setRepeaterData(rep.path, $event)"
|
|
34
34
|
/>
|
|
35
|
+
|
|
36
|
+
<!-- Inside the form so it lands above the submit button, which FormKit renders last. -->
|
|
37
|
+
<slot name="before-submit" />
|
|
35
38
|
</FormKit>
|
|
36
39
|
</div>
|
|
37
40
|
</template>
|
|
@@ -64,6 +67,8 @@ const FIELD_WARNING_KEYS: Record<string, string> = {
|
|
|
64
67
|
const props = defineProps<{
|
|
65
68
|
form: FormkitElement[]
|
|
66
69
|
initialData?: Record<string, unknown>
|
|
70
|
+
// Every caller so far is saving a configuration; the incident form is sending a report.
|
|
71
|
+
submitLabel?: string
|
|
67
72
|
}>()
|
|
68
73
|
|
|
69
74
|
// Clone so the form model never shares references with the Pinia-Colada cache: otherwise
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex flex-col gap-1">
|
|
3
|
+
<MultiSelect
|
|
4
|
+
v-model="selectedKeys"
|
|
5
|
+
:input-id="inputId"
|
|
6
|
+
:options="groupedOptions"
|
|
7
|
+
option-group-label="label"
|
|
8
|
+
option-group-children="items"
|
|
9
|
+
option-label="displayName"
|
|
10
|
+
option-value="key"
|
|
11
|
+
:placeholder="placeholder ?? t('lib.knowledgeCollections.placeholder')"
|
|
12
|
+
:filter="filter"
|
|
13
|
+
:loading="isLoading"
|
|
14
|
+
:disabled="!hasAgent"
|
|
15
|
+
display="chip"
|
|
16
|
+
class="w-full"
|
|
17
|
+
>
|
|
18
|
+
<!-- PrimeVue 4.5 renders the chip-mode placeholder twice while loading with no options yet. -->
|
|
19
|
+
<template
|
|
20
|
+
v-if="currentValue.length === 0"
|
|
21
|
+
#value="{ placeholder: emptyLabel }"
|
|
22
|
+
>
|
|
23
|
+
{{ emptyLabel }}
|
|
24
|
+
</template>
|
|
25
|
+
<template #optiongroup="{ option }">
|
|
26
|
+
<div class="flex items-center gap-2">
|
|
27
|
+
<Icon
|
|
28
|
+
name="mage:database"
|
|
29
|
+
size="1.2em"
|
|
30
|
+
/>
|
|
31
|
+
<span>{{ option.label }}</span>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
<template #option="{ option }">
|
|
35
|
+
<div class="flex items-center gap-2">
|
|
36
|
+
<Icon
|
|
37
|
+
name="mage:folder"
|
|
38
|
+
size="1.2em"
|
|
39
|
+
/>
|
|
40
|
+
<span>{{ option.displayName }}</span>
|
|
41
|
+
</div>
|
|
42
|
+
</template>
|
|
43
|
+
</MultiSelect>
|
|
44
|
+
<small class="text-surface-500">
|
|
45
|
+
{{ hint }}
|
|
46
|
+
</small>
|
|
47
|
+
</div>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<script setup lang="ts">
|
|
51
|
+
import { getAgentInstance, getDatabases } from '@core/sdk/client'
|
|
52
|
+
|
|
53
|
+
import type { DatabaseDto } from '@core/sdk/client'
|
|
54
|
+
import type { FormKitNode } from '@formkit/core'
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* A collection is only addressable as a (database, collection) pair — the same name may exist in more
|
|
58
|
+
* than one database — so the form value is a list of pairs, the shape `RAGStartEvent.selected_namespaces`
|
|
59
|
+
* takes. PrimeVue selects on a primitive, hence the `database/collection` key used inside this component.
|
|
60
|
+
*/
|
|
61
|
+
interface BucketNamespacePair {
|
|
62
|
+
bucket_name: string
|
|
63
|
+
namespace_name: string
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface AgentRefValue {
|
|
67
|
+
agent_class?: string | null
|
|
68
|
+
agent_id?: string | null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** One retriever's vector store, as it is saved in the referenced agent's configuration. */
|
|
72
|
+
interface VectorStoreConfig {
|
|
73
|
+
collection_name?: string
|
|
74
|
+
index_namespaces?: string[]
|
|
75
|
+
all_namespaces?: boolean
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface CollectionOption {
|
|
79
|
+
key: string
|
|
80
|
+
displayName: string
|
|
81
|
+
pair: BucketNamespacePair
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface CollectionGroup {
|
|
85
|
+
label: string
|
|
86
|
+
items: CollectionOption[]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface KnowledgeCollectionSelectorProps {
|
|
90
|
+
context: {
|
|
91
|
+
node: {
|
|
92
|
+
input: (value: BucketNamespacePair[] | null) => void
|
|
93
|
+
at: (address: string) => FormKitNode | null | undefined
|
|
94
|
+
}
|
|
95
|
+
value?: BucketNamespacePair[] | null
|
|
96
|
+
attrs: Record<string, unknown>
|
|
97
|
+
id?: string
|
|
98
|
+
agentRef?: string
|
|
99
|
+
placeholder?: string
|
|
100
|
+
filter?: boolean
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const props = defineProps<KnowledgeCollectionSelectorProps>()
|
|
105
|
+
const { t } = useI18n()
|
|
106
|
+
const { tenantId } = useTenant()
|
|
107
|
+
|
|
108
|
+
const agentRefPath = computed(() => props.context.agentRef)
|
|
109
|
+
const placeholder = computed(() => props.context.placeholder)
|
|
110
|
+
const filter = computed(() => props.context.filter ?? true)
|
|
111
|
+
const inputId = computed(() => `${props.context.id ?? 'knowledge-collections'}-select`)
|
|
112
|
+
|
|
113
|
+
const agentRef = ref<AgentRefValue | null>(null)
|
|
114
|
+
const collections = ref<BucketNamespacePair[]>([])
|
|
115
|
+
const databaseNames = ref<Record<string, string>>({})
|
|
116
|
+
const collectionNames = ref<Record<string, string>>({})
|
|
117
|
+
const isLoading = ref(false)
|
|
118
|
+
|
|
119
|
+
const hasAgent = computed(() => !!agentRef.value?.agent_class && !!agentRef.value?.agent_id)
|
|
120
|
+
|
|
121
|
+
const currentValue = computed<BucketNamespacePair[]>(() => props.context.value ?? [])
|
|
122
|
+
|
|
123
|
+
function keyOf(pair: BucketNamespacePair): string {
|
|
124
|
+
return `${pair.bucket_name}/${pair.namespace_name}`
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function collectionLabel(pair: BucketNamespacePair): string {
|
|
128
|
+
return collectionNames.value[keyOf(pair)] || pair.namespace_name
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const groupedOptions = computed<CollectionGroup[]>(() => {
|
|
132
|
+
const byDatabase = new Map<string, CollectionOption[]>()
|
|
133
|
+
for (const pair of collections.value) {
|
|
134
|
+
const options = byDatabase.get(pair.bucket_name) ?? []
|
|
135
|
+
options.push({
|
|
136
|
+
key: keyOf(pair),
|
|
137
|
+
displayName: collectionLabel(pair),
|
|
138
|
+
pair,
|
|
139
|
+
})
|
|
140
|
+
byDatabase.set(pair.bucket_name, options)
|
|
141
|
+
}
|
|
142
|
+
const groups = [...byDatabase.entries()].map(([database, items]) => ({
|
|
143
|
+
label: databaseNames.value[database] || database,
|
|
144
|
+
items,
|
|
145
|
+
}))
|
|
146
|
+
|
|
147
|
+
// PrimeVue labels a chip from the matching option, so a selection the agent does not retrieve from
|
|
148
|
+
// would otherwise render as its remove icon and nothing else. It is listed under its own group,
|
|
149
|
+
// qualified by database because that is usually what went wrong — the selection was made against a
|
|
150
|
+
// different agent — and so the narrowing the run still applies stays visible enough to act on.
|
|
151
|
+
const available = new Set(collections.value.map(keyOf))
|
|
152
|
+
const unavailable = currentValue.value.filter(pair => !available.has(keyOf(pair)))
|
|
153
|
+
if (unavailable.length === 0) return groups
|
|
154
|
+
|
|
155
|
+
return [...groups, {
|
|
156
|
+
label: t('lib.knowledgeCollections.unavailable'),
|
|
157
|
+
items: unavailable.map(pair => ({
|
|
158
|
+
key: keyOf(pair),
|
|
159
|
+
displayName: `${databaseNames.value[pair.bucket_name] || pair.bucket_name} / ${collectionLabel(pair)}`,
|
|
160
|
+
pair,
|
|
161
|
+
})),
|
|
162
|
+
}]
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
// A selection saved before the referenced agent lost a collection would silently disappear from the
|
|
166
|
+
// chips on load, so it stays listed until the user changes the selection themselves.
|
|
167
|
+
const selectedKeys = computed({
|
|
168
|
+
get: () => currentValue.value.map(keyOf),
|
|
169
|
+
set: (keys: string[]) => {
|
|
170
|
+
const byKey = new Map(collections.value.map(pair => [keyOf(pair), pair]))
|
|
171
|
+
props.context.node.input(keys.map(key => byKey.get(key) ?? currentValue.value.find(pair => keyOf(pair) === key))
|
|
172
|
+
.filter((pair): pair is BucketNamespacePair => !!pair))
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
const hint = computed(() => {
|
|
177
|
+
if (!agentRefPath.value) return t('lib.knowledgeCollections.noSource')
|
|
178
|
+
if (!hasAgent.value) return t('lib.knowledgeCollections.noAgent')
|
|
179
|
+
if (!isLoading.value && collections.value.length === 0) return t('lib.knowledgeCollections.empty')
|
|
180
|
+
return t('lib.knowledgeCollections.help')
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* The collections the referenced agent actually retrieves from: the namespaces each of its retrievers
|
|
185
|
+
* names, or — for a retriever scoped to a whole database — every namespace that database holds. Anything
|
|
186
|
+
* outside this set would be dropped at runtime and the reply answered from nothing, which is why the
|
|
187
|
+
* catalogue alone is not offered here.
|
|
188
|
+
*/
|
|
189
|
+
function collectionsFromRetrievers(configuration: Record<string, unknown>, databases: DatabaseDto[]): BucketNamespacePair[] {
|
|
190
|
+
const retrievers = Array.isArray(configuration.retrievers) ? configuration.retrievers : []
|
|
191
|
+
const pairs: BucketNamespacePair[] = []
|
|
192
|
+
const seen = new Set<string>()
|
|
193
|
+
|
|
194
|
+
for (const retriever of retrievers) {
|
|
195
|
+
const store = (retriever as Record<string, unknown>)?.vector_store as VectorStoreConfig | undefined
|
|
196
|
+
const database = store?.collection_name
|
|
197
|
+
if (!database) continue
|
|
198
|
+
|
|
199
|
+
const namespaces = store?.all_namespaces
|
|
200
|
+
? (databases.find(entry => entry.name === database)?.namespaces ?? []).map(namespace => namespace.name)
|
|
201
|
+
: (store?.index_namespaces ?? [])
|
|
202
|
+
|
|
203
|
+
for (const namespace of namespaces) {
|
|
204
|
+
const pair = { bucket_name: database, namespace_name: namespace }
|
|
205
|
+
const key = keyOf(pair)
|
|
206
|
+
if (seen.has(key)) continue
|
|
207
|
+
seen.add(key)
|
|
208
|
+
pairs.push(pair)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return pairs
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function loadCollections() {
|
|
215
|
+
const agentClass = agentRef.value?.agent_class
|
|
216
|
+
const agentId = agentRef.value?.agent_id
|
|
217
|
+
if (!agentClass || !agentId) {
|
|
218
|
+
collections.value = []
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
isLoading.value = true
|
|
223
|
+
try {
|
|
224
|
+
const [instance, databases] = await Promise.all([
|
|
225
|
+
getAgentInstance({
|
|
226
|
+
composable: '$fetch',
|
|
227
|
+
path: { tenant_id: tenantId.value!, agent_class: agentClass, agent_id: agentId },
|
|
228
|
+
}),
|
|
229
|
+
getDatabases({ composable: '$fetch', path: { tenant_id: tenantId.value! } }),
|
|
230
|
+
])
|
|
231
|
+
databaseNames.value = Object.fromEntries(
|
|
232
|
+
databases.map(database => [database.name, database.display_name || database.name]),
|
|
233
|
+
)
|
|
234
|
+
collectionNames.value = Object.fromEntries(
|
|
235
|
+
databases.flatMap(database => database.namespaces
|
|
236
|
+
.filter(namespace => namespace.display_name)
|
|
237
|
+
.map(namespace => [keyOf({ bucket_name: database.name, namespace_name: namespace.name }), namespace.display_name!])),
|
|
238
|
+
)
|
|
239
|
+
collections.value = collectionsFromRetrievers(instance.configuration ?? {}, databases)
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
console.error(`Failed to load knowledge collections for "${agentClass}/${agentId}":`, error)
|
|
243
|
+
collections.value = []
|
|
244
|
+
}
|
|
245
|
+
finally {
|
|
246
|
+
isLoading.value = false
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* The path arrives relative to the form root and is anchored here, never on the backend: FormKit compiles any
|
|
252
|
+
* schema string beginning with `$` as an expression, so a path shipped as `$root.…` is evaluated against the form
|
|
253
|
+
* data and reaches this component as `undefined`.
|
|
254
|
+
*/
|
|
255
|
+
function readAgentRef(): AgentRefValue | null {
|
|
256
|
+
if (!agentRefPath.value) return null
|
|
257
|
+
return (props.context.node.at(`$root.${agentRefPath.value}`)?.value as AgentRefValue | undefined) ?? null
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function syncAgentRef() {
|
|
261
|
+
const next = readAgentRef()
|
|
262
|
+
if (next?.agent_class === agentRef.value?.agent_class && next?.agent_id === agentRef.value?.agent_id) return
|
|
263
|
+
agentRef.value = next
|
|
264
|
+
loadCollections()
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// The agent lives elsewhere on the form — a sibling group here, a different step in other layouts — so the
|
|
268
|
+
// only dependable signal that it changed is the root form committing. Values on FormKit nodes are not Vue
|
|
269
|
+
// reactive, and re-reading on every commit is cheap because `syncAgentRef` compares before refetching.
|
|
270
|
+
let rootNode: FormKitNode | null | undefined
|
|
271
|
+
let receipt: string | undefined
|
|
272
|
+
onMounted(() => {
|
|
273
|
+
syncAgentRef()
|
|
274
|
+
rootNode = props.context.node.at('$root')
|
|
275
|
+
receipt = rootNode?.on('commit', syncAgentRef)
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
onUnmounted(() => {
|
|
279
|
+
if (receipt) rootNode?.off(receipt)
|
|
280
|
+
})
|
|
281
|
+
</script>
|