@cat-factory/app 0.309.0 → 0.310.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.
- package/README.md +11 -2
- package/app/components/assistant/AssistantModal.vue +5 -4
- package/app/components/auth/BackendMisconfiguredScreen.vue +4 -3
- package/app/components/auth/LoginScreen.vue +40 -26
- package/app/components/auth/ResetPasswordScreen.vue +9 -4
- package/app/components/auth/UserMenu.vue +4 -3
- package/app/components/binaryCandidates/BinaryCandidatesWindow.vue +34 -23
- package/app/components/binaryOutput/StoredAssetView.vue +8 -6
- package/app/components/board/AddTaskModal.vue +16 -15
- package/app/components/board/AgentFailureCard.vue +12 -9
- package/app/components/board/AgentFailureHistory.vue +18 -9
- package/app/components/board/CreateInitiativeModal.vue +5 -4
- package/app/components/board/FailureDetail.vue +22 -12
- package/app/components/board/ReviewFrictionDialog.vue +4 -3
- package/app/components/board/nodes/BlockNode.vue +17 -15
- package/app/components/board/nodes/DecisionBadge.vue +4 -3
- package/app/components/board/nodes/FrameSwimlanes.vue +4 -3
- package/app/components/board/nodes/TaskCard.vue +12 -7
- package/app/components/board/nodes/TaskPipelineMini.vue +9 -7
- package/app/components/bootstrap/AdoptionReviewModal.vue +30 -21
- package/app/components/bootstrap/BootstrapModal.vue +3 -3
- package/app/components/brainstorm/BrainstormWindow.vue +5 -3
- package/app/components/bugFishing/BugFishingWindow.vue +49 -27
- package/app/components/clarity/ClarityReviewWindow.vue +5 -3
- package/app/components/common/CopyButton.vue +12 -11
- package/app/components/common/IconButton.vue +34 -9
- package/app/components/context/ContextAttachmentFields.vue +23 -12
- package/app/components/documents/ContextDocumentPicker.vue +12 -9
- package/app/components/documents/DocumentImportModal.vue +4 -3
- package/app/components/documents/DocumentOriginLink.vue +12 -9
- package/app/components/documents/DocumentSyncState.vue +3 -3
- package/app/components/documents/RepoContextDocPicker.vue +4 -3
- package/app/components/environments/EnvironmentStatusPanel.vue +4 -3
- package/app/components/followUp/FollowUpWindow.vue +9 -6
- package/app/components/forkDecision/ForkDecisionWindow.vue +71 -80
- package/app/components/foundational/FoundationalServiceCatalogList.vue +3 -2
- package/app/components/foundational/FoundationalServiceRegistry.vue +7 -6
- package/app/components/foundational/FoundationalServiceSources.vue +7 -6
- package/app/components/fragments/FragmentLibraryManager.vue +5 -4
- package/app/components/fragments/FragmentSelector.vue +12 -9
- package/app/components/gates/GateFailingCheckList.vue +4 -3
- package/app/components/gates/GateResultView.vue +17 -12
- package/app/components/github/AddServiceFromRepoModal.vue +11 -7
- package/app/components/github/GitHubOnboarding.vue +7 -2
- package/app/components/github/GitHubPanel.vue +9 -6
- package/app/components/github/RepoTreeBrowser.vue +15 -12
- package/app/components/humanTest/HumanTestWindow.vue +13 -9
- package/app/components/initiative/InitiativePlanReview.vue +28 -18
- package/app/components/initiative/InitiativeTrackerWindow.vue +171 -124
- package/app/components/judge/JudgeResultView.vue +5 -3
- package/app/components/kaizen/KaizenPanel.vue +67 -53
- package/app/components/layout/AccountTeamSettings.vue +9 -9
- package/app/components/layout/AppearanceSwitcher.vue +4 -3
- package/app/components/layout/BoardSwitcher.vue +10 -8
- package/app/components/layout/BoardToolbar.vue +5 -4
- package/app/components/layout/CommandBar.vue +4 -3
- package/app/components/layout/DefaultTestEnvBanner.vue +4 -3
- package/app/components/layout/IntegrationsHub.vue +8 -6
- package/app/components/layout/LanguageSwitcher.vue +4 -3
- package/app/components/layout/ModelProvidersHub.vue +4 -3
- package/app/components/layout/NotificationsInbox.vue +40 -30
- package/app/components/layout/PersonalSetupModal.vue +4 -3
- package/app/components/layout/RolePrompt.vue +4 -3
- package/app/components/layout/SideBar.vue +4 -3
- package/app/components/layout/TranslationWarningBanner.vue +4 -3
- package/app/components/layout/UiModeSwitcher.vue +8 -6
- package/app/components/layout/UiRoleSwitcher.vue +8 -6
- package/app/components/layout/WorkspaceMembersSettings.vue +2 -2
- package/app/components/media/ArtifactLightbox.vue +69 -39
- package/app/components/media/ImageCompare.vue +69 -74
- package/app/components/observability/OutcomeFilterChips.vue +5 -4
- package/app/components/observability/RunFailureSummary.vue +8 -6
- package/app/components/observability/StepModelActivity.vue +5 -3
- package/app/components/observability/ToolCallList.vue +4 -2
- package/app/components/outcome/OutcomeSummaryWindow.vue +5 -4
- package/app/components/palettes/AgentPalette.vue +18 -14
- package/app/components/panels/AgentStepDetail.vue +30 -19
- package/app/components/panels/ObservabilityPanel.vue +149 -114
- package/app/components/panels/OperatorDashboardPanel.vue +99 -91
- package/app/components/panels/ReportsPanel.vue +64 -61
- package/app/components/panels/ResultWindowShell.vue +148 -134
- package/app/components/panels/StepContainerStatus.vue +9 -9
- package/app/components/panels/StepDelegatedStatus.vue +11 -9
- package/app/components/panels/StepRestartControl.vue +3 -2
- package/app/components/panels/inspector/EpicChildren.vue +4 -3
- package/app/components/panels/inspector/FrontendConfig.vue +3 -2
- package/app/components/panels/inspector/InspectorSection.vue +22 -17
- package/app/components/panels/inspector/ServiceConnections.vue +3 -2
- package/app/components/panels/inspector/ServiceTestConfig.vue +5 -4
- package/app/components/panels/inspector/TaskExecution.vue +5 -4
- package/app/components/panels/inspector/TaskRunSettings.vue +10 -6
- package/app/components/pipeline/EstimateThresholdFields.vue +13 -10
- package/app/components/pipeline/GateConfigFields.vue +14 -18
- package/app/components/pipeline/PipelineBuilder.vue +90 -77
- package/app/components/pipeline/PipelinePicker.vue +8 -6
- package/app/components/pipeline/PipelineProgress.vue +26 -21
- package/app/components/prReview/PrReviewWindow.vue +46 -25
- package/app/components/providers/ApiKeysSection.vue +4 -3
- package/app/components/ralph/RalphLoopResultView.vue +4 -3
- package/app/components/requirements/RequirementsReviewWindow.vue +10 -6
- package/app/components/riskPolicy/RiskPolicyPicker.vue +8 -6
- package/app/components/sandbox/SandboxPanel.vue +73 -54
- package/app/components/settings/CloudflareHandlerSection.vue +33 -30
- package/app/components/settings/ConsensusGroupsSection.vue +40 -30
- package/app/components/settings/InfraHandlersConfigurator.vue +16 -13
- package/app/components/settings/InfrastructureBackendPicker.vue +17 -17
- package/app/components/settings/IssueTrackerPanel.vue +21 -6
- package/app/components/settings/LocalModelEndpointsPanel.vue +3 -2
- package/app/components/settings/ModelConfigurationPanel.vue +9 -8
- package/app/components/settings/OpenRouterCatalogPanel.vue +4 -3
- package/app/components/settings/ProviderPreferenceEditor.vue +5 -6
- package/app/components/settings/RiskPolicyEditorRow.vue +3 -2
- package/app/components/settings/ServiceFragmentDefaultsPanel.vue +10 -8
- package/app/components/skills/ReviewSkillQueue.vue +4 -3
- package/app/components/skills/SkillLibraryManager.vue +7 -6
- package/app/components/slack/SlackPanel.vue +9 -5
- package/app/components/spec/ServiceSpecWindow.vue +4 -3
- package/app/components/tasks/ContextIssuePicker.vue +12 -9
- package/app/components/tasks/TaskContextIssues.vue +4 -3
- package/app/components/testing/TestReportWindow.vue +14 -8
- package/app/components/theme/ThemeImportModal.vue +2 -2
- package/app/components/visualConfirm/VisualConfirmationWindow.vue +62 -35
- package/i18n/locales/de.json +7 -3
- package/i18n/locales/en.json +7 -3
- package/i18n/locales/es.json +7 -3
- package/i18n/locales/fr.json +7 -3
- package/i18n/locales/he.json +7 -3
- package/i18n/locales/it.json +7 -3
- package/i18n/locales/ja.json +7 -3
- package/i18n/locales/pl.json +7 -3
- package/i18n/locales/tr.json +7 -3
- package/i18n/locales/uk.json +7 -3
- package/package.json +2 -2
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
import InputGateNotice from '~/components/inputGate/InputGateNotice.vue'
|
|
31
31
|
import RunDetailLoadState from '~/components/panels/RunDetailLoadState.vue'
|
|
32
32
|
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
33
|
+
import IconButton from '~/components/common/IconButton.vue'
|
|
33
34
|
|
|
34
35
|
// Detail overlay for a single pipeline step. Opened by clicking an agent in the
|
|
35
36
|
// inspector list (TaskExecution) or the focus-view pipeline (PipelineProgress) via
|
|
@@ -408,7 +409,9 @@ async function copyOutput() {
|
|
|
408
409
|
</SectionLabel>
|
|
409
410
|
</div>
|
|
410
411
|
<nav class="flex-1 space-y-0.5 overflow-auto px-2 py-3">
|
|
411
|
-
<
|
|
412
|
+
<UButton
|
|
413
|
+
color="neutral"
|
|
414
|
+
variant="ghost"
|
|
412
415
|
class="block w-full truncate rounded-md px-2 py-1 text-start text-sm transition"
|
|
413
416
|
:class="
|
|
414
417
|
activeId === 'step-details'
|
|
@@ -418,8 +421,10 @@ async function copyOutput() {
|
|
|
418
421
|
@click="goTo('step-details')"
|
|
419
422
|
>
|
|
420
423
|
{{ t('panels.stepDetail.details') }}
|
|
421
|
-
</
|
|
422
|
-
<
|
|
424
|
+
</UButton>
|
|
425
|
+
<UButton
|
|
426
|
+
color="neutral"
|
|
427
|
+
variant="ghost"
|
|
423
428
|
v-for="s in tocSections"
|
|
424
429
|
:key="s.id"
|
|
425
430
|
class="block w-full truncate rounded-md px-2 py-1 text-start text-sm transition"
|
|
@@ -433,7 +438,7 @@ async function copyOutput() {
|
|
|
433
438
|
@click="goTo(s.id)"
|
|
434
439
|
>
|
|
435
440
|
{{ s.title }}
|
|
436
|
-
</
|
|
441
|
+
</UButton>
|
|
437
442
|
</nav>
|
|
438
443
|
</aside>
|
|
439
444
|
|
|
@@ -471,24 +476,24 @@ async function copyOutput() {
|
|
|
471
476
|
<UIcon name="i-lucide-alert-triangle" class="me-1 h-3 w-3" />
|
|
472
477
|
{{ t('panels.stepDetail.decisionRequired') }}
|
|
473
478
|
</UBadge>
|
|
474
|
-
<
|
|
479
|
+
<IconButton
|
|
475
480
|
v-if="outline.sections.length"
|
|
476
481
|
:icon="allCollapsed ? 'i-lucide-unfold-vertical' : 'i-lucide-fold-vertical'"
|
|
477
482
|
color="neutral"
|
|
478
483
|
variant="ghost"
|
|
479
484
|
size="sm"
|
|
480
|
-
:
|
|
485
|
+
:label="
|
|
481
486
|
allCollapsed ? t('panels.stepDetail.expandAll') : t('panels.stepDetail.collapseAll')
|
|
482
487
|
"
|
|
483
488
|
@click="setAll(!allCollapsed)"
|
|
484
489
|
/>
|
|
485
|
-
<
|
|
490
|
+
<IconButton
|
|
486
491
|
v-if="hasOutput"
|
|
487
492
|
icon="i-lucide-copy"
|
|
488
493
|
color="neutral"
|
|
489
494
|
variant="ghost"
|
|
490
495
|
size="sm"
|
|
491
|
-
:
|
|
496
|
+
:label="t('panels.stepDetail.copyRawOutput')"
|
|
492
497
|
@click="copyOutput"
|
|
493
498
|
/>
|
|
494
499
|
<!-- Restart the pipeline from this step (shared two-click confirm; resetting
|
|
@@ -500,12 +505,12 @@ async function copyOutput() {
|
|
|
500
505
|
:step-index="ctx?.stepIndex ?? null"
|
|
501
506
|
@restarted="close"
|
|
502
507
|
/>
|
|
503
|
-
<
|
|
508
|
+
<IconButton
|
|
504
509
|
icon="i-lucide-x"
|
|
505
510
|
color="neutral"
|
|
506
511
|
variant="ghost"
|
|
507
512
|
size="sm"
|
|
508
|
-
:
|
|
513
|
+
:label="t('panels.stepDetail.closeEsc')"
|
|
509
514
|
@click="close"
|
|
510
515
|
/>
|
|
511
516
|
</div>
|
|
@@ -782,9 +787,11 @@ async function copyOutput() {
|
|
|
782
787
|
:ref="(el) => (sectionEls[s.id] = el as HTMLElement | null)"
|
|
783
788
|
class="scroll-mt-4"
|
|
784
789
|
>
|
|
785
|
-
<
|
|
790
|
+
<UButton
|
|
791
|
+
color="neutral"
|
|
792
|
+
variant="ghost"
|
|
786
793
|
v-if="s.depth > 0"
|
|
787
|
-
class="group flex w-full items-center gap-2 rounded-md py-1 text-start transition hover:text-highlighted"
|
|
794
|
+
class="group flex w-full items-center gap-2 rounded-md px-0 py-1 text-start transition hover:bg-transparent hover:text-highlighted"
|
|
788
795
|
@click="toggle(s.id)"
|
|
789
796
|
>
|
|
790
797
|
<UIcon
|
|
@@ -797,7 +804,7 @@ async function copyOutput() {
|
|
|
797
804
|
:class="s.depth <= 1 ? 'text-lg' : s.depth === 2 ? 'text-base' : 'text-sm'"
|
|
798
805
|
v-html="s.titleHtml"
|
|
799
806
|
/>
|
|
800
|
-
</
|
|
807
|
+
</UButton>
|
|
801
808
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
|
802
809
|
<div
|
|
803
810
|
v-show="!collapsed[s.id]"
|
|
@@ -914,13 +921,17 @@ async function copyOutput() {
|
|
|
914
921
|
<SectionLabel>
|
|
915
922
|
{{ t('panels.stepDetail.commentN', { number: idx + 1 }) }}
|
|
916
923
|
</SectionLabel>
|
|
917
|
-
<
|
|
918
|
-
|
|
919
|
-
|
|
924
|
+
<IconButton
|
|
925
|
+
color="neutral"
|
|
926
|
+
variant="ghost"
|
|
927
|
+
icon="i-lucide-x"
|
|
928
|
+
:label="t('panels.stepDetail.removeComment')"
|
|
929
|
+
:ui="{
|
|
930
|
+
base: 'p-0 text-dimmed transition hover:bg-transparent hover:text-app-error-400',
|
|
931
|
+
leadingIcon: 'h-3.5 w-3.5',
|
|
932
|
+
}"
|
|
920
933
|
@click="removeComment(idx)"
|
|
921
|
-
|
|
922
|
-
<UIcon name="i-lucide-x" class="h-3.5 w-3.5" />
|
|
923
|
-
</button>
|
|
934
|
+
/>
|
|
924
935
|
</div>
|
|
925
936
|
<pre
|
|
926
937
|
class="mb-1 max-h-20 overflow-auto whitespace-pre-wrap rounded-sm bg-app-950/50 p-1.5 text-3xs text-muted"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, nextTick, reactive, ref, watch } from 'vue'
|
|
3
3
|
import { onKeyStroke } from '@vueuse/core'
|
|
4
|
+
import type { TableColumn } from '@nuxt/ui'
|
|
4
5
|
import { isLlmWarningFinishReason } from '@cat-factory/contracts'
|
|
5
6
|
import type {
|
|
6
7
|
AgentContextSnapshot,
|
|
@@ -30,6 +31,7 @@ import OutcomeFilterChips from '~/components/observability/OutcomeFilterChips.vu
|
|
|
30
31
|
import RunFailureSummary from '~/components/observability/RunFailureSummary.vue'
|
|
31
32
|
import ToolCallList from '~/components/observability/ToolCallList.vue'
|
|
32
33
|
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
34
|
+
import IconButton from '~/components/common/IconButton.vue'
|
|
33
35
|
|
|
34
36
|
/** No run selected: the same empty, NOT-truncated trajectory the store answers with. */
|
|
35
37
|
const EMPTY_TRAJECTORY: RunToolCallTrajectory = Object.freeze({
|
|
@@ -166,6 +168,22 @@ function openToolsView() {
|
|
|
166
168
|
ensureTrajectoryLoaded()
|
|
167
169
|
}
|
|
168
170
|
|
|
171
|
+
const viewTabs = computed(() => [
|
|
172
|
+
{ value: 'calls', label: t('observability.modelActivity') },
|
|
173
|
+
{ value: 'tools', label: t('observability.toolCalls.title') },
|
|
174
|
+
{ value: 'context', label: t('observability.providedContext') },
|
|
175
|
+
{ value: 'search', label: t('observability.webSearch') },
|
|
176
|
+
])
|
|
177
|
+
|
|
178
|
+
/** The tools view has a side effect (lazy trajectory load), so selection routes through here. */
|
|
179
|
+
function selectView(next: string) {
|
|
180
|
+
if (next === 'tools') {
|
|
181
|
+
openToolsView()
|
|
182
|
+
return
|
|
183
|
+
}
|
|
184
|
+
view.value = next as typeof view.value
|
|
185
|
+
}
|
|
186
|
+
|
|
169
187
|
/**
|
|
170
188
|
* Load the trajectory the first time it is actually looked at.
|
|
171
189
|
*
|
|
@@ -411,6 +429,23 @@ const costCurrency = computed(
|
|
|
411
429
|
const showCost = computed(
|
|
412
430
|
() => !!costCurrency.value && phaseRows.value.some((p) => p.costEstimate != null),
|
|
413
431
|
)
|
|
432
|
+
// Column definitions rather than hand-written `<th>`s. The cost column stays conditional on the
|
|
433
|
+
// same signal: a deployment with no rate table must not be shown a column of em dashes.
|
|
434
|
+
const phaseColumns = computed<TableColumn<(typeof phaseRows.value)[number]>[]>(() => [
|
|
435
|
+
{ id: 'phase' },
|
|
436
|
+
{ id: 'turns' },
|
|
437
|
+
{ id: 'tokens' },
|
|
438
|
+
...(showCost.value ? [{ id: 'cost' } as TableColumn<(typeof phaseRows.value)[number]>] : []),
|
|
439
|
+
// `aria-sort` needs BOTH halves: UTable asks `enableSorting && column.getCanSort()`, and
|
|
440
|
+
// `getCanSort()` is false on a column with no accessor, so `enableSorting` alone emitted
|
|
441
|
+
// nothing and the header silently stopped stating the order. The rows arrive in this order
|
|
442
|
+
// from the rollup, so `manualSorting` below keeps TanStack from re-deriving it: the
|
|
443
|
+
// declaration MARKS the order, it does not produce it, and nothing here offers a sort control.
|
|
444
|
+
{ id: 'carryCost', accessorKey: 'carryCostTokens', enableSorting: true },
|
|
445
|
+
])
|
|
446
|
+
/** The order the rollup already returns, stated so the header can say which column it is. */
|
|
447
|
+
const PHASE_SORTING = [{ id: 'carryCost', desc: true }]
|
|
448
|
+
const PHASE_SORTING_OPTIONS = { manualSorting: true }
|
|
414
449
|
/**
|
|
415
450
|
* The run's estimated cost, folded from the same SQL rollup the phase table shows — NOT from
|
|
416
451
|
* the capped call list the token totals beside it use, which would silently under-report a run
|
|
@@ -521,44 +556,17 @@ function exportJson() {
|
|
|
521
556
|
</p>
|
|
522
557
|
</div>
|
|
523
558
|
<div class="ms-auto flex items-center gap-1.5">
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
class="rounded-md px-2.5 py-1 transition"
|
|
536
|
-
:class="
|
|
537
|
-
view === 'tools' ? 'bg-elevated text-app-100' : 'text-muted hover:text-default'
|
|
538
|
-
"
|
|
539
|
-
@click="openToolsView()"
|
|
540
|
-
>
|
|
541
|
-
{{ t('observability.toolCalls.title') }}
|
|
542
|
-
</button>
|
|
543
|
-
<button
|
|
544
|
-
class="rounded-md px-2.5 py-1 transition"
|
|
545
|
-
:class="
|
|
546
|
-
view === 'context' ? 'bg-elevated text-app-100' : 'text-muted hover:text-default'
|
|
547
|
-
"
|
|
548
|
-
@click="view = 'context'"
|
|
549
|
-
>
|
|
550
|
-
{{ t('observability.providedContext') }}
|
|
551
|
-
</button>
|
|
552
|
-
<button
|
|
553
|
-
class="rounded-md px-2.5 py-1 transition"
|
|
554
|
-
:class="
|
|
555
|
-
view === 'search' ? 'bg-elevated text-app-100' : 'text-muted hover:text-default'
|
|
556
|
-
"
|
|
557
|
-
@click="view = 'search'"
|
|
558
|
-
>
|
|
559
|
-
{{ t('observability.webSearch') }}
|
|
560
|
-
</button>
|
|
561
|
-
</div>
|
|
559
|
+
<!-- Four VIEWS of the same run, which is what tabs mean. The trajectory is loaded
|
|
560
|
+
lazily the first time the tools view is opened, so the change is watched rather
|
|
561
|
+
than bound straight to `view`. -->
|
|
562
|
+
<UTabs
|
|
563
|
+
:model-value="view"
|
|
564
|
+
:items="viewTabs"
|
|
565
|
+
:content="false"
|
|
566
|
+
size="xs"
|
|
567
|
+
class="me-1"
|
|
568
|
+
@update:model-value="selectView(String($event))"
|
|
569
|
+
/>
|
|
562
570
|
<UButton
|
|
563
571
|
v-if="view === 'calls'"
|
|
564
572
|
icon="i-lucide-download"
|
|
@@ -572,12 +580,12 @@ function exportJson() {
|
|
|
572
580
|
>
|
|
573
581
|
{{ t('observability.exportJson') }}
|
|
574
582
|
</UButton>
|
|
575
|
-
<
|
|
583
|
+
<IconButton
|
|
576
584
|
icon="i-lucide-x"
|
|
577
585
|
color="neutral"
|
|
578
586
|
variant="ghost"
|
|
579
587
|
size="sm"
|
|
580
|
-
:
|
|
588
|
+
:label="t('observability.closeEsc')"
|
|
581
589
|
@click="close"
|
|
582
590
|
/>
|
|
583
591
|
</div>
|
|
@@ -732,76 +740,99 @@ function exportJson() {
|
|
|
732
740
|
{{ t('observability.phase.noRollup') }}
|
|
733
741
|
</p>
|
|
734
742
|
<div v-else class="mt-3 overflow-x-auto">
|
|
735
|
-
<
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
743
|
+
<UTable
|
|
744
|
+
:data="phaseRows"
|
|
745
|
+
:columns="phaseColumns"
|
|
746
|
+
:sorting="PHASE_SORTING"
|
|
747
|
+
:sorting-options="PHASE_SORTING_OPTIONS"
|
|
748
|
+
:ui="{
|
|
749
|
+
base: 'min-w-[32rem] text-xs',
|
|
750
|
+
th: 'px-3 py-1.5',
|
|
751
|
+
td: 'px-3 py-1.5 text-xs whitespace-normal',
|
|
752
|
+
}"
|
|
753
|
+
>
|
|
754
|
+
<template #phase-header>
|
|
755
|
+
{{ t('observability.phase.columns.phase') }}
|
|
756
|
+
</template>
|
|
757
|
+
<template #turns-header>
|
|
758
|
+
<span class="block text-end">
|
|
759
|
+
{{ t('observability.phase.columns.turns') }}
|
|
760
|
+
</span>
|
|
761
|
+
</template>
|
|
762
|
+
<template #tokens-header>
|
|
763
|
+
<span class="block text-end">
|
|
764
|
+
{{ t('observability.phase.columns.tokensInOut') }}
|
|
765
|
+
</span>
|
|
766
|
+
</template>
|
|
767
|
+
<template #cost-header>
|
|
768
|
+
<span class="block text-end" :title="t('observability.phase.costHint')">
|
|
769
|
+
{{ t('observability.phase.columns.cost') }}
|
|
770
|
+
</span>
|
|
771
|
+
</template>
|
|
772
|
+
<!-- The sort key, MARKED as one. Rows lead with carry cost rather than
|
|
773
|
+
with tokens, and the two orders genuinely differ: a phase that runs
|
|
774
|
+
late carries almost nothing however much it spent (nothing after it
|
|
775
|
+
re-sends its context). Leaving that implicit invites reading row 1
|
|
776
|
+
as "the phase that burned the most", which is the neighbouring
|
|
777
|
+
column. -->
|
|
778
|
+
<template #carryCost-header>
|
|
779
|
+
<span class="block text-end" :title="t('observability.phase.carryCostHint')">
|
|
780
|
+
{{ t('observability.phase.columns.carryCost') }} ↓
|
|
781
|
+
</span>
|
|
782
|
+
</template>
|
|
783
|
+
<template #phase-cell="{ row }">
|
|
784
|
+
<span :class="row.original.phase ? '' : 'text-muted italic'">
|
|
785
|
+
{{ phaseLabel(row.original.phase) }}
|
|
786
|
+
</span>
|
|
787
|
+
<span v-if="!row.original.phase" class="ms-1.5 text-2xs text-app-600">
|
|
788
|
+
{{ t('observability.phase.unattributedHint') }}
|
|
789
|
+
</span>
|
|
790
|
+
<UBadge
|
|
791
|
+
v-if="row.original.errors"
|
|
792
|
+
color="error"
|
|
793
|
+
variant="subtle"
|
|
794
|
+
size="sm"
|
|
795
|
+
class="ms-2"
|
|
796
|
+
>
|
|
797
|
+
{{
|
|
798
|
+
t(
|
|
799
|
+
'observability.metricsBar.errors',
|
|
800
|
+
{ count: row.original.errors },
|
|
801
|
+
row.original.errors,
|
|
802
|
+
)
|
|
803
|
+
}}
|
|
804
|
+
</UBadge>
|
|
805
|
+
</template>
|
|
806
|
+
<template #turns-cell="{ row }">
|
|
807
|
+
<span class="block text-end tabular-nums text-toned">{{
|
|
808
|
+
row.original.calls
|
|
809
|
+
}}</span>
|
|
810
|
+
</template>
|
|
811
|
+
<template #tokens-cell="{ row }">
|
|
812
|
+
<span class="block text-end tabular-nums text-toned">
|
|
813
|
+
{{ formatTokens(totalInputTokens(row.original)) }}↑
|
|
814
|
+
{{ formatTokens(row.original.completionTokens) }}↓
|
|
815
|
+
</span>
|
|
816
|
+
</template>
|
|
817
|
+
<!-- An em dash, not 0: this phase's model had no rate, and a zero here
|
|
818
|
+
would read as a phase that cost nothing. -->
|
|
819
|
+
<template #cost-cell="{ row }">
|
|
820
|
+
<span class="block text-end tabular-nums text-toned">
|
|
821
|
+
{{ formatCost(row.original.costEstimate, costCurrency) ?? '—' }}
|
|
822
|
+
</span>
|
|
823
|
+
</template>
|
|
824
|
+
<template #carryCost-cell="{ row }">
|
|
825
|
+
<span class="block text-end tabular-nums text-toned">
|
|
826
|
+
{{ formatTokens(row.original.carryCostTokens) }}
|
|
827
|
+
<span
|
|
828
|
+
v-if="carryShare(row.original.carryCostTokens) !== null"
|
|
829
|
+
class="text-app-600"
|
|
830
|
+
>
|
|
831
|
+
· {{ carryShare(row.original.carryCostTokens) }}%
|
|
832
|
+
</span>
|
|
833
|
+
</span>
|
|
834
|
+
</template>
|
|
835
|
+
</UTable>
|
|
805
836
|
</div>
|
|
806
837
|
</section>
|
|
807
838
|
|
|
@@ -863,7 +894,9 @@ function exportJson() {
|
|
|
863
894
|
class="overflow-hidden rounded-xl border border-default bg-default/40"
|
|
864
895
|
:class="!c.ok ? 'border-app-error-900/60' : ''"
|
|
865
896
|
>
|
|
866
|
-
<
|
|
897
|
+
<UButton
|
|
898
|
+
color="neutral"
|
|
899
|
+
variant="ghost"
|
|
867
900
|
class="flex w-full items-center gap-3 px-4 py-2.5 text-start transition hover:bg-default/70"
|
|
868
901
|
@click="toggle(c)"
|
|
869
902
|
>
|
|
@@ -935,7 +968,7 @@ function exportJson() {
|
|
|
935
968
|
}}</span>
|
|
936
969
|
<span class="hidden text-app-600 md:inline">{{ clock(c.createdAt) }}</span>
|
|
937
970
|
</div>
|
|
938
|
-
</
|
|
971
|
+
</UButton>
|
|
939
972
|
|
|
940
973
|
<div v-if="expanded[c.id]" class="border-t border-default px-4 py-3 space-y-3">
|
|
941
974
|
<p v-if="c.errorMessage" class="text-xs text-app-error-400">
|
|
@@ -1088,7 +1121,9 @@ function exportJson() {
|
|
|
1088
1121
|
:key="s.id"
|
|
1089
1122
|
class="overflow-hidden rounded-xl border border-default bg-default/40"
|
|
1090
1123
|
>
|
|
1091
|
-
<
|
|
1124
|
+
<UButton
|
|
1125
|
+
color="neutral"
|
|
1126
|
+
variant="ghost"
|
|
1092
1127
|
class="flex w-full items-center gap-3 px-4 py-2.5 text-start transition hover:bg-default/70"
|
|
1093
1128
|
@click="toggleCtx(s)"
|
|
1094
1129
|
>
|
|
@@ -1115,7 +1150,7 @@ function exportJson() {
|
|
|
1115
1150
|
}}</span>
|
|
1116
1151
|
<span class="hidden text-app-600 md:inline">{{ clock(s.createdAt) }}</span>
|
|
1117
1152
|
</div>
|
|
1118
|
-
</
|
|
1153
|
+
</UButton>
|
|
1119
1154
|
|
|
1120
1155
|
<div v-if="expandedCtx[s.id]" class="border-t border-default px-4 py-3 space-y-3">
|
|
1121
1156
|
<div>
|