arkaos 3.20.0 → 3.21.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/VERSION +1 -1
- package/dashboard/app/pages/agents/compare.vue +225 -0
- package/dashboard/app/pages/agents/index.vue +14 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.21.0
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// PR87c v3.21.0 — Compare two agents side-by-side.
|
|
3
|
+
//
|
|
4
|
+
// Driven by `?ids=a,b` query string. Reads both agent payloads via
|
|
5
|
+
// /api/agents/{id} and renders identity / DNA / knowledge / comms in
|
|
6
|
+
// two columns. Cells where the values differ get a subtle warning
|
|
7
|
+
// tint so the operator can spot deltas quickly.
|
|
8
|
+
|
|
9
|
+
const route = useRoute()
|
|
10
|
+
const { fetchApi } = useApi()
|
|
11
|
+
|
|
12
|
+
const ids = computed<string[]>(() => {
|
|
13
|
+
const raw = route.query.ids
|
|
14
|
+
const str = Array.isArray(raw) ? raw.join(',') : (raw ?? '')
|
|
15
|
+
return String(str).split(',').map((s) => s.trim()).filter(Boolean).slice(0, 2)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
interface AgentDetail {
|
|
19
|
+
id: string
|
|
20
|
+
name?: string
|
|
21
|
+
role?: string
|
|
22
|
+
department?: string
|
|
23
|
+
tier?: number
|
|
24
|
+
model?: string
|
|
25
|
+
mbti?: string
|
|
26
|
+
disc?: { primary?: string, secondary?: string }
|
|
27
|
+
enneagram?: { type?: number, wing?: number }
|
|
28
|
+
big_five?: {
|
|
29
|
+
openness?: number
|
|
30
|
+
conscientiousness?: number
|
|
31
|
+
extraversion?: number
|
|
32
|
+
agreeableness?: number
|
|
33
|
+
neuroticism?: number
|
|
34
|
+
}
|
|
35
|
+
expertise?: { domains?: string[], frameworks?: string[], depth?: string, years_equivalent?: number }
|
|
36
|
+
mental_models?: { primary?: string[], secondary?: string[] }
|
|
37
|
+
communication?: {
|
|
38
|
+
tone?: string
|
|
39
|
+
vocabulary_level?: string
|
|
40
|
+
preferred_format?: string
|
|
41
|
+
language?: string
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { data: a, status: aStatus } = fetchApi<AgentDetail>(
|
|
46
|
+
() => ids.value[0] ? `/api/agents/${ids.value[0]}` : '',
|
|
47
|
+
)
|
|
48
|
+
const { data: b, status: bStatus } = fetchApi<AgentDetail>(
|
|
49
|
+
() => ids.value[1] ? `/api/agents/${ids.value[1]}` : '',
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
const loading = computed(() => aStatus.value === 'pending' || bStatus.value === 'pending')
|
|
53
|
+
const errorMsg = computed(() => {
|
|
54
|
+
if (ids.value.length < 2) return 'Pass two agent ids via ?ids=a,b'
|
|
55
|
+
if (a.value && (a.value as any).error) return `Left agent: ${(a.value as any).error}`
|
|
56
|
+
if (b.value && (b.value as any).error) return `Right agent: ${(b.value as any).error}`
|
|
57
|
+
return null
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
function diffClass(left: unknown, right: unknown): string {
|
|
61
|
+
return left !== right
|
|
62
|
+
? 'bg-yellow-500/10 border-yellow-500/30'
|
|
63
|
+
: ''
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function listDiffClass(left: unknown[] | undefined, right: unknown[] | undefined): string {
|
|
67
|
+
const a = JSON.stringify([...(left ?? [])].sort())
|
|
68
|
+
const b = JSON.stringify([...(right ?? [])].sort())
|
|
69
|
+
return a !== b ? 'bg-yellow-500/10 border-yellow-500/30' : ''
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const bigFiveKeys = ['openness', 'conscientiousness', 'extraversion', 'agreeableness', 'neuroticism'] as const
|
|
73
|
+
</script>
|
|
74
|
+
|
|
75
|
+
<template>
|
|
76
|
+
<UDashboardPanel id="agents-compare">
|
|
77
|
+
<template #header>
|
|
78
|
+
<UDashboardNavbar title="Compare agents">
|
|
79
|
+
<template #leading>
|
|
80
|
+
<UButton icon="i-lucide-arrow-left" variant="ghost" size="sm" to="/agents" aria-label="Back" />
|
|
81
|
+
</template>
|
|
82
|
+
<template #trailing>
|
|
83
|
+
<UBadge label="2-way" variant="subtle" size="sm" />
|
|
84
|
+
</template>
|
|
85
|
+
</UDashboardNavbar>
|
|
86
|
+
</template>
|
|
87
|
+
|
|
88
|
+
<template #body>
|
|
89
|
+
<div v-if="errorMsg" class="p-6 text-center text-sm text-error">
|
|
90
|
+
{{ errorMsg }}
|
|
91
|
+
</div>
|
|
92
|
+
<div v-else-if="loading" class="p-6 text-center text-sm text-muted">
|
|
93
|
+
<UIcon name="i-lucide-loader-2" class="size-4 animate-spin inline" /> Loading…
|
|
94
|
+
</div>
|
|
95
|
+
<div v-else-if="a && b" class="space-y-4 max-w-6xl">
|
|
96
|
+
<section class="grid grid-cols-2 gap-3">
|
|
97
|
+
<div class="rounded-lg border border-default p-4">
|
|
98
|
+
<p class="text-xs text-muted">Left</p>
|
|
99
|
+
<h2 class="text-xl font-bold">{{ a.name }}</h2>
|
|
100
|
+
<p class="text-sm text-muted">{{ a.role }} · {{ a.department }}</p>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="rounded-lg border border-default p-4">
|
|
103
|
+
<p class="text-xs text-muted">Right</p>
|
|
104
|
+
<h2 class="text-xl font-bold">{{ b.name }}</h2>
|
|
105
|
+
<p class="text-sm text-muted">{{ b.role }} · {{ b.department }}</p>
|
|
106
|
+
</div>
|
|
107
|
+
</section>
|
|
108
|
+
|
|
109
|
+
<h3 class="text-sm font-semibold uppercase tracking-wide text-muted pt-2">Identity</h3>
|
|
110
|
+
<div class="grid grid-cols-2 gap-3">
|
|
111
|
+
<div :class="['rounded-lg border p-3', diffClass(a.tier, b.tier)]">
|
|
112
|
+
<p class="text-xs text-muted">Tier</p>
|
|
113
|
+
<p class="text-sm font-mono">{{ a.tier ?? '—' }}</p>
|
|
114
|
+
</div>
|
|
115
|
+
<div :class="['rounded-lg border p-3', diffClass(a.tier, b.tier)]">
|
|
116
|
+
<p class="text-xs text-muted">Tier</p>
|
|
117
|
+
<p class="text-sm font-mono">{{ b.tier ?? '—' }}</p>
|
|
118
|
+
</div>
|
|
119
|
+
<div :class="['rounded-lg border p-3', diffClass(a.model, b.model)]">
|
|
120
|
+
<p class="text-xs text-muted">Model</p>
|
|
121
|
+
<p class="text-sm font-mono">{{ a.model ?? '—' }}</p>
|
|
122
|
+
</div>
|
|
123
|
+
<div :class="['rounded-lg border p-3', diffClass(a.model, b.model)]">
|
|
124
|
+
<p class="text-xs text-muted">Model</p>
|
|
125
|
+
<p class="text-sm font-mono">{{ b.model ?? '—' }}</p>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<h3 class="text-sm font-semibold uppercase tracking-wide text-muted pt-2">Behavioural DNA</h3>
|
|
130
|
+
<div class="grid grid-cols-2 gap-3">
|
|
131
|
+
<div :class="['rounded-lg border p-3', diffClass(a.mbti, b.mbti)]">
|
|
132
|
+
<p class="text-xs text-muted">MBTI</p>
|
|
133
|
+
<p class="text-lg font-mono font-bold">{{ a.mbti ?? '—' }}</p>
|
|
134
|
+
</div>
|
|
135
|
+
<div :class="['rounded-lg border p-3', diffClass(a.mbti, b.mbti)]">
|
|
136
|
+
<p class="text-xs text-muted">MBTI</p>
|
|
137
|
+
<p class="text-lg font-mono font-bold">{{ b.mbti ?? '—' }}</p>
|
|
138
|
+
</div>
|
|
139
|
+
<div :class="['rounded-lg border p-3', diffClass(`${a.disc?.primary}/${a.disc?.secondary}`, `${b.disc?.primary}/${b.disc?.secondary}`)]">
|
|
140
|
+
<p class="text-xs text-muted">DISC</p>
|
|
141
|
+
<p class="text-lg font-mono font-bold">{{ a.disc?.primary ?? '?' }}/{{ a.disc?.secondary ?? '?' }}</p>
|
|
142
|
+
</div>
|
|
143
|
+
<div :class="['rounded-lg border p-3', diffClass(`${a.disc?.primary}/${a.disc?.secondary}`, `${b.disc?.primary}/${b.disc?.secondary}`)]">
|
|
144
|
+
<p class="text-xs text-muted">DISC</p>
|
|
145
|
+
<p class="text-lg font-mono font-bold">{{ b.disc?.primary ?? '?' }}/{{ b.disc?.secondary ?? '?' }}</p>
|
|
146
|
+
</div>
|
|
147
|
+
<div :class="['rounded-lg border p-3', diffClass(`${a.enneagram?.type}w${a.enneagram?.wing}`, `${b.enneagram?.type}w${b.enneagram?.wing}`)]">
|
|
148
|
+
<p class="text-xs text-muted">Enneagram</p>
|
|
149
|
+
<p class="text-lg font-mono font-bold">{{ a.enneagram?.type ?? '?' }}w{{ a.enneagram?.wing ?? '?' }}</p>
|
|
150
|
+
</div>
|
|
151
|
+
<div :class="['rounded-lg border p-3', diffClass(`${a.enneagram?.type}w${a.enneagram?.wing}`, `${b.enneagram?.type}w${b.enneagram?.wing}`)]">
|
|
152
|
+
<p class="text-xs text-muted">Enneagram</p>
|
|
153
|
+
<p class="text-lg font-mono font-bold">{{ b.enneagram?.type ?? '?' }}w{{ b.enneagram?.wing ?? '?' }}</p>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<h3 class="text-sm font-semibold uppercase tracking-wide text-muted pt-2">Big Five (OCEAN)</h3>
|
|
158
|
+
<div class="space-y-1">
|
|
159
|
+
<div v-for="k in bigFiveKeys" :key="k" class="grid grid-cols-2 gap-3">
|
|
160
|
+
<div :class="['rounded-lg border p-2 flex items-center gap-3', diffClass(a.big_five?.[k], b.big_five?.[k])]">
|
|
161
|
+
<span class="text-xs text-muted w-36 shrink-0 capitalize">{{ k }}</span>
|
|
162
|
+
<span class="font-mono text-sm">{{ a.big_five?.[k] ?? '—' }}</span>
|
|
163
|
+
</div>
|
|
164
|
+
<div :class="['rounded-lg border p-2 flex items-center gap-3', diffClass(a.big_five?.[k], b.big_five?.[k])]">
|
|
165
|
+
<span class="text-xs text-muted w-36 shrink-0 capitalize">{{ k }}</span>
|
|
166
|
+
<span class="font-mono text-sm">{{ b.big_five?.[k] ?? '—' }}</span>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
<h3 class="text-sm font-semibold uppercase tracking-wide text-muted pt-2">Expertise domains</h3>
|
|
172
|
+
<div class="grid grid-cols-2 gap-3">
|
|
173
|
+
<div :class="['rounded-lg border p-3', listDiffClass(a.expertise?.domains, b.expertise?.domains)]">
|
|
174
|
+
<ul class="list-disc list-inside text-sm space-y-1">
|
|
175
|
+
<li v-for="d in a.expertise?.domains" :key="d">{{ d }}</li>
|
|
176
|
+
<li v-if="!a.expertise?.domains?.length" class="list-none text-muted italic">none</li>
|
|
177
|
+
</ul>
|
|
178
|
+
</div>
|
|
179
|
+
<div :class="['rounded-lg border p-3', listDiffClass(a.expertise?.domains, b.expertise?.domains)]">
|
|
180
|
+
<ul class="list-disc list-inside text-sm space-y-1">
|
|
181
|
+
<li v-for="d in b.expertise?.domains" :key="d">{{ d }}</li>
|
|
182
|
+
<li v-if="!b.expertise?.domains?.length" class="list-none text-muted italic">none</li>
|
|
183
|
+
</ul>
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
<h3 class="text-sm font-semibold uppercase tracking-wide text-muted pt-2">Frameworks</h3>
|
|
188
|
+
<div class="grid grid-cols-2 gap-3">
|
|
189
|
+
<div :class="['rounded-lg border p-3', listDiffClass(a.expertise?.frameworks, b.expertise?.frameworks)]">
|
|
190
|
+
<ul class="list-disc list-inside text-sm space-y-1">
|
|
191
|
+
<li v-for="f in a.expertise?.frameworks" :key="f">{{ f }}</li>
|
|
192
|
+
<li v-if="!a.expertise?.frameworks?.length" class="list-none text-muted italic">none</li>
|
|
193
|
+
</ul>
|
|
194
|
+
</div>
|
|
195
|
+
<div :class="['rounded-lg border p-3', listDiffClass(a.expertise?.frameworks, b.expertise?.frameworks)]">
|
|
196
|
+
<ul class="list-disc list-inside text-sm space-y-1">
|
|
197
|
+
<li v-for="f in b.expertise?.frameworks" :key="f">{{ f }}</li>
|
|
198
|
+
<li v-if="!b.expertise?.frameworks?.length" class="list-none text-muted italic">none</li>
|
|
199
|
+
</ul>
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
<h3 class="text-sm font-semibold uppercase tracking-wide text-muted pt-2">Mental models (primary)</h3>
|
|
204
|
+
<div class="grid grid-cols-2 gap-3">
|
|
205
|
+
<div :class="['rounded-lg border p-3', listDiffClass(a.mental_models?.primary, b.mental_models?.primary)]">
|
|
206
|
+
<ul class="list-disc list-inside text-sm space-y-1">
|
|
207
|
+
<li v-for="m in a.mental_models?.primary" :key="m">{{ m }}</li>
|
|
208
|
+
<li v-if="!a.mental_models?.primary?.length" class="list-none text-muted italic">none</li>
|
|
209
|
+
</ul>
|
|
210
|
+
</div>
|
|
211
|
+
<div :class="['rounded-lg border p-3', listDiffClass(a.mental_models?.primary, b.mental_models?.primary)]">
|
|
212
|
+
<ul class="list-disc list-inside text-sm space-y-1">
|
|
213
|
+
<li v-for="m in b.mental_models?.primary" :key="m">{{ m }}</li>
|
|
214
|
+
<li v-if="!b.mental_models?.primary?.length" class="list-none text-muted italic">none</li>
|
|
215
|
+
</ul>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
|
|
219
|
+
<p class="text-xs text-muted pt-4 italic">
|
|
220
|
+
Cells with a yellow tint differ between the two agents.
|
|
221
|
+
</p>
|
|
222
|
+
</div>
|
|
223
|
+
</template>
|
|
224
|
+
</UDashboardPanel>
|
|
225
|
+
</template>
|
|
@@ -220,6 +220,12 @@ const departmentMoveOptions = [
|
|
|
220
220
|
onSelect: () => bulkMove(d),
|
|
221
221
|
}))
|
|
222
222
|
|
|
223
|
+
function openCompare() {
|
|
224
|
+
if (selected.value.size !== 2) return
|
|
225
|
+
const ids = Array.from(selected.value).slice(0, 2).join(',')
|
|
226
|
+
navigateTo(`/agents/compare?ids=${ids}`)
|
|
227
|
+
}
|
|
228
|
+
|
|
223
229
|
async function bulkMove(targetDept: string) {
|
|
224
230
|
if (selected.value.size === 0) return
|
|
225
231
|
const ids = Array.from(selected.value)
|
|
@@ -552,6 +558,14 @@ async function undoTrashIds(ids: string[]) {
|
|
|
552
558
|
@click="clearSelection"
|
|
553
559
|
/>
|
|
554
560
|
<div class="h-5 w-px bg-default" />
|
|
561
|
+
<UButton
|
|
562
|
+
label="Compare"
|
|
563
|
+
icon="i-lucide-columns-2"
|
|
564
|
+
size="sm"
|
|
565
|
+
variant="soft"
|
|
566
|
+
:disabled="selected.size !== 2"
|
|
567
|
+
@click="openCompare"
|
|
568
|
+
/>
|
|
555
569
|
<UDropdownMenu :items="departmentMoveOptions">
|
|
556
570
|
<UButton
|
|
557
571
|
label="Move to..."
|
package/package.json
CHANGED