@cat-factory/app 0.99.0 → 0.100.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/app/components/board/FailureHistoryList.vue +4 -3
- package/app/components/board/StepExecutionHistory.vue +100 -0
- package/app/components/panels/AgentStepDetail.vue +17 -6
- package/app/types/execution.ts +1 -0
- package/i18n/locales/en.json +2 -0
- package/i18n/locales/es.json +2 -0
- package/i18n/locales/fr.json +2 -0
- package/i18n/locales/he.json +2 -0
- package/i18n/locales/ja.json +2 -0
- package/i18n/locales/pl.json +2 -0
- package/i18n/locales/tr.json +2 -0
- package/i18n/locales/uk.json +2 -0
- package/package.json +2 -2
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
// The newest-first list of failed-attempt entries (timestamp + message + hint + collapsible
|
|
3
|
-
// detail)
|
|
4
|
-
//
|
|
5
|
-
//
|
|
3
|
+
// detail) behind the task-inspector's "previous errors" disclosure (AgentFailureHistory).
|
|
4
|
+
// Presentational only — the caller decides which trail to pass and how to reveal it. (The
|
|
5
|
+
// step-detail overlay's per-step "execution history" uses StepExecutionHistory instead, which
|
|
6
|
+
// merges these failures with the successful outputs a restart superseded.)
|
|
6
7
|
import type { AgentFailure } from '~/types/domain'
|
|
7
8
|
import FailureDetail from '~/components/board/FailureDetail.vue'
|
|
8
9
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// The step-detail overlay's per-step "execution history": a newest-first, MERGED timeline of
|
|
3
|
+
// this step's SUCCESSFUL prior outputs (discarded by a restart) and its FAILED attempts — so
|
|
4
|
+
// the history surfaces what superseded attempts PRODUCED, not only the errors. Presentational
|
|
5
|
+
// only: the caller passes both trails already narrowed to the step (by `stepIndex`).
|
|
6
|
+
import type { AgentFailure, PriorStepOutput } from '~/types/domain'
|
|
7
|
+
import FailureDetail from '~/components/board/FailureDetail.vue'
|
|
8
|
+
import CopyButton from '~/components/common/CopyButton.vue'
|
|
9
|
+
|
|
10
|
+
const props = defineProps<{ failures: AgentFailure[]; outputs: PriorStepOutput[] }>()
|
|
11
|
+
|
|
12
|
+
const { t, d } = useI18n()
|
|
13
|
+
|
|
14
|
+
type Entry =
|
|
15
|
+
| { kind: 'failure'; key: string; occurredAt: number; failure: AgentFailure }
|
|
16
|
+
| { kind: 'success'; key: string; occurredAt: number; output: PriorStepOutput }
|
|
17
|
+
|
|
18
|
+
// Merge both trails and show newest first — the most recent attempt is the most relevant.
|
|
19
|
+
// Each entry's `key` is its position within its OWN trail (both are append-only, so that
|
|
20
|
+
// position is a stable identity), not the volatile merged-sort index — and it stays unique
|
|
21
|
+
// even when several entries share a timestamp (a restart can discard many steps with the same
|
|
22
|
+
// clock-fallback `occurredAt`).
|
|
23
|
+
const entries = computed<Entry[]>(() =>
|
|
24
|
+
[
|
|
25
|
+
...props.failures.map(
|
|
26
|
+
(failure, i): Entry => ({
|
|
27
|
+
kind: 'failure',
|
|
28
|
+
key: `failure-${i}`,
|
|
29
|
+
occurredAt: failure.occurredAt,
|
|
30
|
+
failure,
|
|
31
|
+
}),
|
|
32
|
+
),
|
|
33
|
+
...props.outputs.map(
|
|
34
|
+
(output, i): Entry => ({
|
|
35
|
+
kind: 'success',
|
|
36
|
+
key: `success-${i}`,
|
|
37
|
+
occurredAt: output.occurredAt,
|
|
38
|
+
output,
|
|
39
|
+
}),
|
|
40
|
+
),
|
|
41
|
+
].sort((a, b) => b.occurredAt - a.occurredAt),
|
|
42
|
+
)
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<ol class="space-y-2">
|
|
47
|
+
<li
|
|
48
|
+
v-for="entry in entries"
|
|
49
|
+
:key="entry.key"
|
|
50
|
+
class="rounded-md border px-2.5 py-2"
|
|
51
|
+
:class="
|
|
52
|
+
entry.kind === 'success'
|
|
53
|
+
? 'border-emerald-900/60 bg-emerald-950/20'
|
|
54
|
+
: 'border-slate-800/80 bg-slate-950/50'
|
|
55
|
+
"
|
|
56
|
+
:data-testid="
|
|
57
|
+
entry.kind === 'success' ? 'step-history-success-entry' : 'step-history-failure-entry'
|
|
58
|
+
"
|
|
59
|
+
>
|
|
60
|
+
<!-- a superseded SUCCESSFUL attempt: its output, collapsible + copyable -->
|
|
61
|
+
<template v-if="entry.kind === 'success'">
|
|
62
|
+
<div class="flex items-center gap-1.5 text-[10px] text-slate-500">
|
|
63
|
+
<UIcon name="i-lucide-check-circle-2" class="h-3 w-3 shrink-0 text-emerald-400/70" />
|
|
64
|
+
<time>{{ d(new Date(entry.occurredAt), 'long') }}</time>
|
|
65
|
+
<span class="text-emerald-400/80">{{ t('panels.stepDetail.attemptSucceeded') }}</span>
|
|
66
|
+
</div>
|
|
67
|
+
<div class="relative mt-1">
|
|
68
|
+
<CopyButton :text="entry.output.output" class="absolute end-1 top-1 z-10" />
|
|
69
|
+
<pre
|
|
70
|
+
class="max-h-40 overflow-auto whitespace-pre-wrap rounded bg-slate-950/80 p-1.5 pe-9 text-[10px] leading-snug text-slate-300"
|
|
71
|
+
>{{ entry.output.output }}</pre
|
|
72
|
+
>
|
|
73
|
+
</div>
|
|
74
|
+
<p v-if="entry.output.truncated" class="mt-1 text-[10px] text-slate-500">
|
|
75
|
+
{{ t('panels.stepDetail.outputTruncated') }}
|
|
76
|
+
</p>
|
|
77
|
+
</template>
|
|
78
|
+
|
|
79
|
+
<!-- a FAILED attempt: mirrors FailureHistoryList's entry markup -->
|
|
80
|
+
<template v-else>
|
|
81
|
+
<div class="flex items-center gap-1.5 text-[10px] text-slate-500">
|
|
82
|
+
<UIcon name="i-lucide-alert-triangle" class="h-3 w-3 shrink-0 text-rose-400/70" />
|
|
83
|
+
<time>{{ d(new Date(entry.occurredAt), 'long') }}</time>
|
|
84
|
+
</div>
|
|
85
|
+
<p class="mt-1 text-[11px] leading-snug text-slate-300" :title="entry.failure.message">
|
|
86
|
+
{{ entry.failure.message }}
|
|
87
|
+
</p>
|
|
88
|
+
<p v-if="entry.failure.hint" class="mt-1 text-[10px] leading-snug text-slate-500">
|
|
89
|
+
{{ entry.failure.hint }}
|
|
90
|
+
</p>
|
|
91
|
+
<FailureDetail
|
|
92
|
+
:detail="entry.failure.detail"
|
|
93
|
+
:message="entry.failure.message"
|
|
94
|
+
summary-class="text-[10px] text-slate-500 hover:text-slate-300"
|
|
95
|
+
pre-class="bg-slate-950/80 text-[10px] text-slate-400"
|
|
96
|
+
/>
|
|
97
|
+
</template>
|
|
98
|
+
</li>
|
|
99
|
+
</ol>
|
|
100
|
+
</template>
|
|
@@ -11,7 +11,7 @@ import FrontendBindingsResolved from '~/components/panels/inspector/FrontendBind
|
|
|
11
11
|
import { UI_TESTER_AGENT_KIND } from '@cat-factory/contracts'
|
|
12
12
|
import ProvisioningLogsDrawer from '~/components/provisioning/ProvisioningLogsDrawer.vue'
|
|
13
13
|
import IterationCapPrompt from '~/components/pipeline/IterationCapPrompt.vue'
|
|
14
|
-
import
|
|
14
|
+
import StepExecutionHistory from '~/components/board/StepExecutionHistory.vue'
|
|
15
15
|
import { useStepTimer } from '~/composables/useStepTimer'
|
|
16
16
|
import { useStepProse } from '~/composables/useStepProse'
|
|
17
17
|
import { useStepApproval } from '~/composables/useStepApproval'
|
|
@@ -96,6 +96,16 @@ const stepFailures = computed(() => {
|
|
|
96
96
|
if (instance.value?.failure) trail.push(instance.value.failure)
|
|
97
97
|
return trail.filter((f) => f.stepIndex === idx)
|
|
98
98
|
})
|
|
99
|
+
// The positive complement of the failure trail: the SUCCESSFUL outputs a restart discarded
|
|
100
|
+
// for THIS step (each carries the `stepIndex` that produced it), so the history surfaces what
|
|
101
|
+
// superseded attempts produced — not only errors. Merged with `stepFailures` in the timeline.
|
|
102
|
+
const stepOutputs = computed(() => {
|
|
103
|
+
const idx = ctx.value?.stepIndex
|
|
104
|
+
if (idx == null) return []
|
|
105
|
+
return (instance.value?.outputHistory ?? []).filter((o) => o.stepIndex === idx)
|
|
106
|
+
})
|
|
107
|
+
// Whether this step has ANY prior-attempt history (successful outputs and/or failures).
|
|
108
|
+
const hasStepHistory = computed(() => stepFailures.value.length > 0 || stepOutputs.value.length > 0)
|
|
99
109
|
const showHistory = ref(false)
|
|
100
110
|
|
|
101
111
|
// A failed run is no longer executing: a step left mid-flight (state still
|
|
@@ -439,10 +449,10 @@ async function copyOutput() {
|
|
|
439
449
|
/>
|
|
440
450
|
</div>
|
|
441
451
|
|
|
442
|
-
<!-- this step's
|
|
443
|
-
behind a toggle —
|
|
444
|
-
|
|
445
|
-
<div v-if="
|
|
452
|
+
<!-- this step's execution history (the run-level trail narrowed to this step),
|
|
453
|
+
behind a toggle — a merged timeline of the SUCCESSFUL outputs a restart
|
|
454
|
+
superseded and the FAILED attempts, scoped to the step being looked at -->
|
|
455
|
+
<div v-if="hasStepHistory">
|
|
446
456
|
<UButton
|
|
447
457
|
:icon="showHistory ? 'i-lucide-chevron-up' : 'i-lucide-history'"
|
|
448
458
|
variant="ghost"
|
|
@@ -460,10 +470,11 @@ async function copyOutput() {
|
|
|
460
470
|
: t('panels.stepDetail.executionHistory')
|
|
461
471
|
}}
|
|
462
472
|
</UButton>
|
|
463
|
-
<
|
|
473
|
+
<StepExecutionHistory
|
|
464
474
|
v-if="showHistory"
|
|
465
475
|
class="mt-2"
|
|
466
476
|
:failures="stepFailures"
|
|
477
|
+
:outputs="stepOutputs"
|
|
467
478
|
data-testid="step-execution-history"
|
|
468
479
|
/>
|
|
469
480
|
</div>
|
package/app/types/execution.ts
CHANGED
package/i18n/locales/en.json
CHANGED
|
@@ -1027,6 +1027,8 @@
|
|
|
1027
1027
|
"hideInfraAttempts": "Hide infrastructure attempts",
|
|
1028
1028
|
"executionHistory": "Execution history",
|
|
1029
1029
|
"hideExecutionHistory": "Hide execution history",
|
|
1030
|
+
"attemptSucceeded": "Succeeded",
|
|
1031
|
+
"outputTruncated": "Output clipped to keep the run history compact.",
|
|
1030
1032
|
"editingConclusions": "Editing the conclusions",
|
|
1031
1033
|
"editConclusionsPlaceholder": "Edit the agent's conclusions; your edits are saved when you approve…",
|
|
1032
1034
|
"noProseOutput": "This agent produced no prose output.",
|
package/i18n/locales/es.json
CHANGED
|
@@ -984,6 +984,8 @@
|
|
|
984
984
|
"hideInfraAttempts": "Ocultar intentos de infraestructura",
|
|
985
985
|
"executionHistory": "Historial de ejecución",
|
|
986
986
|
"hideExecutionHistory": "Ocultar historial de ejecución",
|
|
987
|
+
"attemptSucceeded": "Correcto",
|
|
988
|
+
"outputTruncated": "Salida recortada para mantener compacto el historial de ejecución.",
|
|
987
989
|
"editingConclusions": "Editando las conclusiones",
|
|
988
990
|
"editConclusionsPlaceholder": "Edita las conclusiones del agente; tus cambios se guardan cuando apruebas…",
|
|
989
991
|
"noProseOutput": "Este agente no produjo salida en prosa.",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -984,6 +984,8 @@
|
|
|
984
984
|
"hideInfraAttempts": "Masquer les tentatives d'infrastructure",
|
|
985
985
|
"executionHistory": "Historique d'exécution",
|
|
986
986
|
"hideExecutionHistory": "Masquer l'historique d'exécution",
|
|
987
|
+
"attemptSucceeded": "Réussi",
|
|
988
|
+
"outputTruncated": "Sortie tronquée pour garder l'historique d'exécution compact.",
|
|
987
989
|
"editingConclusions": "Modification des conclusions",
|
|
988
990
|
"editConclusionsPlaceholder": "Modifiez les conclusions de l'agent ; vos modifications sont enregistrées lorsque vous approuvez…",
|
|
989
991
|
"noProseOutput": "Cet agent n'a produit aucune sortie en texte libre.",
|
package/i18n/locales/he.json
CHANGED
|
@@ -984,6 +984,8 @@
|
|
|
984
984
|
"hideInfraAttempts": "הסתר ניסיונות תשתית",
|
|
985
985
|
"executionHistory": "היסטוריית הרצה",
|
|
986
986
|
"hideExecutionHistory": "הסתר היסטוריית הרצה",
|
|
987
|
+
"attemptSucceeded": "הצליח",
|
|
988
|
+
"outputTruncated": "הפלט נקטע כדי לשמור על היסטוריית ההרצה קומפקטית.",
|
|
987
989
|
"editingConclusions": "עריכת המסקנות",
|
|
988
990
|
"editConclusionsPlaceholder": "ערוך את מסקנות הסוכן; העריכות שלך נשמרות כשתאשר…",
|
|
989
991
|
"noProseOutput": "סוכן זה לא הפיק פלט טקסטואלי.",
|
package/i18n/locales/ja.json
CHANGED
|
@@ -984,6 +984,8 @@
|
|
|
984
984
|
"hideInfraAttempts": "インフラの試行を非表示",
|
|
985
985
|
"executionHistory": "実行履歴",
|
|
986
986
|
"hideExecutionHistory": "実行履歴を非表示",
|
|
987
|
+
"attemptSucceeded": "成功",
|
|
988
|
+
"outputTruncated": "実行履歴を簡潔に保つため出力を切り詰めました。",
|
|
987
989
|
"editingConclusions": "結論を編集中",
|
|
988
990
|
"editConclusionsPlaceholder": "エージェントの結論を編集してください。編集内容は承認時に保存されます…",
|
|
989
991
|
"noProseOutput": "このエージェントは文章出力を生成しませんでした。",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -984,6 +984,8 @@
|
|
|
984
984
|
"hideInfraAttempts": "Ukryj próby infrastrukturalne",
|
|
985
985
|
"executionHistory": "Historia wykonania",
|
|
986
986
|
"hideExecutionHistory": "Ukryj historię wykonania",
|
|
987
|
+
"attemptSucceeded": "Powodzenie",
|
|
988
|
+
"outputTruncated": "Wynik przycięty, aby zachować zwięzłość historii wykonania.",
|
|
987
989
|
"editingConclusions": "Edytowanie wniosków",
|
|
988
990
|
"editConclusionsPlaceholder": "Edytuj wnioski agenta; Twoje zmiany zostaną zapisane po zatwierdzeniu…",
|
|
989
991
|
"noProseOutput": "Ten agent nie wytworzył wyniku tekstowego.",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -984,6 +984,8 @@
|
|
|
984
984
|
"hideInfraAttempts": "Altyapı denemelerini gizle",
|
|
985
985
|
"executionHistory": "Yürütme geçmişi",
|
|
986
986
|
"hideExecutionHistory": "Yürütme geçmişini gizle",
|
|
987
|
+
"attemptSucceeded": "Başarılı",
|
|
988
|
+
"outputTruncated": "Yürütme geçmişini derli toplu tutmak için çıktı kırpıldı.",
|
|
987
989
|
"editingConclusions": "Sonuçlar düzenleniyor",
|
|
988
990
|
"editConclusionsPlaceholder": "Aracının sonuçlarını düzenleyin; düzenlemeleriniz onayladığınızda kaydedilir…",
|
|
989
991
|
"noProseOutput": "Bu aracı herhangi bir metin çıktısı üretmedi.",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -984,6 +984,8 @@
|
|
|
984
984
|
"hideInfraAttempts": "Приховати спроби інфраструктури",
|
|
985
985
|
"executionHistory": "Історія виконання",
|
|
986
986
|
"hideExecutionHistory": "Приховати історію виконання",
|
|
987
|
+
"attemptSucceeded": "Успішно",
|
|
988
|
+
"outputTruncated": "Вивід обрізано, щоб історія виконання залишалася компактною.",
|
|
987
989
|
"editingConclusions": "Редагування висновків",
|
|
988
990
|
"editConclusionsPlaceholder": "Відредагуйте висновки агента; ваші зміни зберігаються після затвердження…",
|
|
989
991
|
"noProseOutput": "Цей агент не створив текстового виводу.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.100.1",
|
|
4
4
|
"description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"valibot": "^1.4.2",
|
|
35
35
|
"vue": "3.5.39",
|
|
36
36
|
"wretch": "^3.0.9",
|
|
37
|
-
"@cat-factory/contracts": "0.
|
|
37
|
+
"@cat-factory/contracts": "0.110.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@toad-contracts/testing": "0.3.2",
|