arkaos 3.17.0 → 3.19.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/core/agents/__pycache__/obsidian_export.cpython-313.pyc +0 -0
- package/core/personas/__pycache__/schema.cpython-313.pyc +0 -0
- package/core/personas/schema.py +4 -0
- package/dashboard/app/components/AgentEditDrawer.vue +15 -0
- package/dashboard/app/components/MarkdownEditor.vue +74 -0
- package/dashboard/app/pages/agents/[id].vue +25 -0
- package/dashboard/app/pages/agents/index.vue +54 -1
- package/dashboard/app/pages/personas/[id].vue +37 -0
- package/dashboard/package.json +1 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/scripts/__pycache__/dashboard-api.cpython-313.pyc +0 -0
- package/scripts/dashboard-api.py +4 -0
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.19.0
|
|
Binary file
|
|
Binary file
|
package/core/personas/schema.py
CHANGED
|
@@ -61,6 +61,10 @@ class Persona(BaseModel):
|
|
|
61
61
|
# Communication
|
|
62
62
|
communication: PersonaCommunication = Field(default_factory=PersonaCommunication)
|
|
63
63
|
|
|
64
|
+
# PR86d v3.18.0 — long-form Markdown bio. Free-text field, never
|
|
65
|
+
# parsed; rendered in the dashboard with `marked` for preview.
|
|
66
|
+
bio_md: str = ""
|
|
67
|
+
|
|
64
68
|
# Metadata
|
|
65
69
|
created_at: str = ""
|
|
66
70
|
updated_at: str = ""
|
|
@@ -58,6 +58,7 @@ interface AgentDraft {
|
|
|
58
58
|
avoid: string[]
|
|
59
59
|
}
|
|
60
60
|
linked_personas: string[]
|
|
61
|
+
bio_md: string
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
const draft = ref<AgentDraft | null>(null)
|
|
@@ -88,6 +89,7 @@ watch(
|
|
|
88
89
|
avoid: agent.communication?.avoid ?? [],
|
|
89
90
|
},
|
|
90
91
|
linked_personas: agent.linked_personas ?? [],
|
|
92
|
+
bio_md: agent.bio_md ?? '',
|
|
91
93
|
}
|
|
92
94
|
dirty.value = false
|
|
93
95
|
} else if (!open) {
|
|
@@ -323,6 +325,7 @@ async function save() {
|
|
|
323
325
|
},
|
|
324
326
|
communication: draft.value.communication,
|
|
325
327
|
linked_personas: draft.value.linked_personas,
|
|
328
|
+
bio_md: draft.value.bio_md,
|
|
326
329
|
}
|
|
327
330
|
const res = await $fetch<{
|
|
328
331
|
id: string
|
|
@@ -653,6 +656,18 @@ const vocabOptions = [
|
|
|
653
656
|
</UFormField>
|
|
654
657
|
</section>
|
|
655
658
|
|
|
659
|
+
<section class="space-y-3">
|
|
660
|
+
<h3 class="text-xs font-semibold uppercase tracking-wider text-muted">
|
|
661
|
+
Bio (Markdown)
|
|
662
|
+
</h3>
|
|
663
|
+
<MarkdownEditor
|
|
664
|
+
:model-value="draft.bio_md"
|
|
665
|
+
:rows="10"
|
|
666
|
+
placeholder="A free-text Markdown bio for this agent — context, voice samples, internal notes."
|
|
667
|
+
@update:model-value="(v: string) => { if (draft) { draft.bio_md = v; markDirty() } }"
|
|
668
|
+
/>
|
|
669
|
+
</section>
|
|
670
|
+
|
|
656
671
|
<section class="space-y-3">
|
|
657
672
|
<h3 class="text-xs font-semibold uppercase tracking-wider text-muted">
|
|
658
673
|
Linked personas
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// PR86d v3.18.0 — Markdown editor with Edit / Preview tabs.
|
|
3
|
+
//
|
|
4
|
+
// Standalone component used in agent + persona edit forms. The model
|
|
5
|
+
// value is the raw Markdown string. Preview is rendered via marked
|
|
6
|
+
// (already a deps after this PR).
|
|
7
|
+
|
|
8
|
+
import { marked } from 'marked'
|
|
9
|
+
|
|
10
|
+
const props = defineProps<{
|
|
11
|
+
modelValue: string
|
|
12
|
+
placeholder?: string
|
|
13
|
+
rows?: number
|
|
14
|
+
}>()
|
|
15
|
+
const emit = defineEmits<{
|
|
16
|
+
(e: 'update:modelValue', value: string): void
|
|
17
|
+
}>()
|
|
18
|
+
|
|
19
|
+
const tab = ref<'edit' | 'preview'>('edit')
|
|
20
|
+
|
|
21
|
+
const value = computed({
|
|
22
|
+
get: () => props.modelValue ?? '',
|
|
23
|
+
set: (v: string) => emit('update:modelValue', v),
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const html = computed(() => {
|
|
27
|
+
if (!value.value.trim()) {
|
|
28
|
+
return '<p class="text-muted italic">Nothing to preview yet.</p>'
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
return marked.parse(value.value, { breaks: true, gfm: true })
|
|
32
|
+
} catch {
|
|
33
|
+
return '<p class="text-error">Markdown parse failed.</p>'
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<div class="space-y-2">
|
|
40
|
+
<div class="flex items-center gap-1 text-xs">
|
|
41
|
+
<button
|
|
42
|
+
type="button"
|
|
43
|
+
class="px-2 py-1 rounded-md transition-colors"
|
|
44
|
+
:class="tab === 'edit' ? 'bg-elevated/60 text-default font-semibold' : 'text-muted hover:text-default'"
|
|
45
|
+
@click="tab = 'edit'"
|
|
46
|
+
>
|
|
47
|
+
Edit
|
|
48
|
+
</button>
|
|
49
|
+
<button
|
|
50
|
+
type="button"
|
|
51
|
+
class="px-2 py-1 rounded-md transition-colors"
|
|
52
|
+
:class="tab === 'preview' ? 'bg-elevated/60 text-default font-semibold' : 'text-muted hover:text-default'"
|
|
53
|
+
@click="tab = 'preview'"
|
|
54
|
+
>
|
|
55
|
+
Preview
|
|
56
|
+
</button>
|
|
57
|
+
<span class="ml-auto text-xs text-muted">
|
|
58
|
+
Markdown · GFM · {{ value.length }} char{{ value.length === 1 ? '' : 's' }}
|
|
59
|
+
</span>
|
|
60
|
+
</div>
|
|
61
|
+
<UTextarea
|
|
62
|
+
v-if="tab === 'edit'"
|
|
63
|
+
v-model="value"
|
|
64
|
+
:rows="rows ?? 8"
|
|
65
|
+
:placeholder="placeholder ?? 'Write a Markdown bio…\n\n# Heading\n- bullets\n**bold**'"
|
|
66
|
+
class="w-full font-mono text-sm"
|
|
67
|
+
/>
|
|
68
|
+
<div
|
|
69
|
+
v-else
|
|
70
|
+
class="rounded-lg border border-default bg-elevated/10 p-4 min-h-[12rem] prose prose-sm dark:prose-invert max-w-none"
|
|
71
|
+
v-html="html"
|
|
72
|
+
/>
|
|
73
|
+
</div>
|
|
74
|
+
</template>
|
|
@@ -65,6 +65,17 @@ function formatRelative(iso: string | null): string {
|
|
|
65
65
|
const favs = useFavorites()
|
|
66
66
|
await favs.load()
|
|
67
67
|
|
|
68
|
+
// PR86d v3.18.0 — render Markdown bio.
|
|
69
|
+
import { marked } from 'marked'
|
|
70
|
+
function markedHtml(src: string): string {
|
|
71
|
+
if (!src?.trim()) return ''
|
|
72
|
+
try {
|
|
73
|
+
return marked.parse(src, { breaks: true, gfm: true }) as string
|
|
74
|
+
} catch {
|
|
75
|
+
return ''
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
68
79
|
// PR86c v3.17.0 — export to Obsidian.
|
|
69
80
|
const exporting = ref(false)
|
|
70
81
|
async function exportToVault() {
|
|
@@ -418,6 +429,20 @@ function formatTokens(n: number): string {
|
|
|
418
429
|
</div>
|
|
419
430
|
</section>
|
|
420
431
|
|
|
432
|
+
<!-- ===== BIO (PR86d) ===== -->
|
|
433
|
+
<section
|
|
434
|
+
v-if="(agent as any).bio_md"
|
|
435
|
+
class="rounded-xl border border-default bg-elevated/10 p-5"
|
|
436
|
+
>
|
|
437
|
+
<h3 class="text-sm font-semibold uppercase tracking-wide text-muted mb-3">
|
|
438
|
+
Bio
|
|
439
|
+
</h3>
|
|
440
|
+
<div
|
|
441
|
+
class="prose prose-sm dark:prose-invert max-w-none"
|
|
442
|
+
v-html="markedHtml((agent as any).bio_md)"
|
|
443
|
+
/>
|
|
444
|
+
</section>
|
|
445
|
+
|
|
421
446
|
<AgentEditDrawer
|
|
422
447
|
v-model="editOpen"
|
|
423
448
|
:agent="agent"
|
|
@@ -91,6 +91,33 @@ const tierOptions = [
|
|
|
91
91
|
{ label: 'Tier 3 — Support', value: '3' }
|
|
92
92
|
]
|
|
93
93
|
|
|
94
|
+
// PR87a v3.19.0 — DNA filters (DISC primary + MBTI group).
|
|
95
|
+
const discFilter = ref<'all' | 'D' | 'I' | 'S' | 'C'>('all')
|
|
96
|
+
const mbtiGroupFilter = ref<'all' | 'analysts' | 'diplomats' | 'sentinels' | 'explorers'>('all')
|
|
97
|
+
|
|
98
|
+
const discOptions = [
|
|
99
|
+
{ label: 'All DISC', value: 'all' },
|
|
100
|
+
{ label: 'D — Dominance', value: 'D' },
|
|
101
|
+
{ label: 'I — Influence', value: 'I' },
|
|
102
|
+
{ label: 'S — Steadiness', value: 'S' },
|
|
103
|
+
{ label: 'C — Conscientiousness', value: 'C' },
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
const mbtiGroupOptions = [
|
|
107
|
+
{ label: 'All MBTI groups', value: 'all' },
|
|
108
|
+
{ label: 'Analysts (NT)', value: 'analysts' },
|
|
109
|
+
{ label: 'Diplomats (NF)', value: 'diplomats' },
|
|
110
|
+
{ label: 'Sentinels (S__J)', value: 'sentinels' },
|
|
111
|
+
{ label: 'Explorers (S__P)', value: 'explorers' },
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
const MBTI_GROUPS: Record<string, string> = {
|
|
115
|
+
INTJ: 'analysts', INTP: 'analysts', ENTJ: 'analysts', ENTP: 'analysts',
|
|
116
|
+
INFJ: 'diplomats', INFP: 'diplomats', ENFJ: 'diplomats', ENFP: 'diplomats',
|
|
117
|
+
ISTJ: 'sentinels', ISFJ: 'sentinels', ESTJ: 'sentinels', ESFJ: 'sentinels',
|
|
118
|
+
ISTP: 'explorers', ISFP: 'explorers', ESTP: 'explorers', ESFP: 'explorers',
|
|
119
|
+
}
|
|
120
|
+
|
|
94
121
|
const filteredAgents = computed(() => {
|
|
95
122
|
let result = agents.value
|
|
96
123
|
const query = search.value.toLowerCase()
|
|
@@ -111,6 +138,16 @@ const filteredAgents = computed(() => {
|
|
|
111
138
|
result = result.filter(agent => String(agent.tier) === tierFilter.value)
|
|
112
139
|
}
|
|
113
140
|
|
|
141
|
+
if (discFilter.value !== 'all') {
|
|
142
|
+
result = result.filter(agent => agent.disc?.primary === discFilter.value)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (mbtiGroupFilter.value !== 'all') {
|
|
146
|
+
result = result.filter(
|
|
147
|
+
agent => MBTI_GROUPS[(agent.mbti ?? '').toUpperCase()] === mbtiGroupFilter.value,
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
114
151
|
if (favoritesOnly.value) {
|
|
115
152
|
result = result.filter(agent => favs.isAgentFavorite(agent.id))
|
|
116
153
|
}
|
|
@@ -127,7 +164,7 @@ const paginatedAgents = computed(() => {
|
|
|
127
164
|
|
|
128
165
|
const totalPages = computed(() => Math.max(1, Math.ceil(totalFiltered.value / pageSize)))
|
|
129
166
|
|
|
130
|
-
watch([search, departmentFilter, tierFilter], () => {
|
|
167
|
+
watch([search, departmentFilter, tierFilter, discFilter, mbtiGroupFilter], () => {
|
|
131
168
|
page.value = 1
|
|
132
169
|
})
|
|
133
170
|
|
|
@@ -381,6 +418,22 @@ async function undoTrashIds(ids: string[]) {
|
|
|
381
418
|
aria-label="Filter by tier"
|
|
382
419
|
/>
|
|
383
420
|
|
|
421
|
+
<USelect
|
|
422
|
+
v-model="discFilter"
|
|
423
|
+
:items="discOptions"
|
|
424
|
+
placeholder="DISC"
|
|
425
|
+
class="min-w-36"
|
|
426
|
+
aria-label="Filter by DISC primary"
|
|
427
|
+
/>
|
|
428
|
+
|
|
429
|
+
<USelect
|
|
430
|
+
v-model="mbtiGroupFilter"
|
|
431
|
+
:items="mbtiGroupOptions"
|
|
432
|
+
placeholder="MBTI group"
|
|
433
|
+
class="min-w-44"
|
|
434
|
+
aria-label="Filter by MBTI group"
|
|
435
|
+
/>
|
|
436
|
+
|
|
384
437
|
<UButton
|
|
385
438
|
:label="favoritesOnly ? 'All' : 'Favorites'"
|
|
386
439
|
:icon="favoritesOnly ? 'i-lucide-star' : 'i-lucide-star'"
|
|
@@ -230,6 +230,17 @@ const suggestingField = ref<SuggestField | null>(null)
|
|
|
230
230
|
const favs = useFavorites()
|
|
231
231
|
await favs.load()
|
|
232
232
|
|
|
233
|
+
// PR86d v3.18.0 — render Markdown bio.
|
|
234
|
+
import { marked } from 'marked'
|
|
235
|
+
function markedHtml(src: string): string {
|
|
236
|
+
if (!src?.trim()) return ''
|
|
237
|
+
try {
|
|
238
|
+
return marked.parse(src, { breaks: true, gfm: true }) as string
|
|
239
|
+
} catch {
|
|
240
|
+
return ''
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
233
244
|
// PR85a v3.11.0 — Clone to Agent dialog.
|
|
234
245
|
const cloneOpen = ref(false)
|
|
235
246
|
function onCloned(agentId: string) {
|
|
@@ -560,6 +571,20 @@ const vocabOptions = [
|
|
|
560
571
|
</div>
|
|
561
572
|
</section>
|
|
562
573
|
|
|
574
|
+
<!-- BIO (PR86d) -->
|
|
575
|
+
<section
|
|
576
|
+
v-if="(detail as any).bio_md"
|
|
577
|
+
class="rounded-xl border border-default bg-elevated/10 p-5"
|
|
578
|
+
>
|
|
579
|
+
<h3 class="text-sm font-semibold uppercase tracking-wide text-muted mb-3">
|
|
580
|
+
Bio
|
|
581
|
+
</h3>
|
|
582
|
+
<div
|
|
583
|
+
class="prose prose-sm dark:prose-invert max-w-none"
|
|
584
|
+
v-html="markedHtml((detail as any).bio_md)"
|
|
585
|
+
/>
|
|
586
|
+
</section>
|
|
587
|
+
|
|
563
588
|
<!-- TABS -->
|
|
564
589
|
<UTabs :items="tabs" default-value="dna" class="w-full">
|
|
565
590
|
<template #content="{ item }">
|
|
@@ -937,6 +962,18 @@ const vocabOptions = [
|
|
|
937
962
|
</UFormField>
|
|
938
963
|
</section>
|
|
939
964
|
|
|
965
|
+
<section class="space-y-3">
|
|
966
|
+
<h3 class="text-xs font-semibold uppercase tracking-wider text-muted">
|
|
967
|
+
Bio (Markdown)
|
|
968
|
+
</h3>
|
|
969
|
+
<MarkdownEditor
|
|
970
|
+
:model-value="(draft as any).bio_md ?? ''"
|
|
971
|
+
:rows="10"
|
|
972
|
+
placeholder="A free-text Markdown bio for this persona — voice samples, context, references."
|
|
973
|
+
@update:model-value="(v: string) => { if (draft) { (draft as any).bio_md = v; markDirty() } }"
|
|
974
|
+
/>
|
|
975
|
+
</section>
|
|
976
|
+
|
|
940
977
|
<section class="space-y-3">
|
|
941
978
|
<div class="flex items-center justify-between">
|
|
942
979
|
<h3 class="text-xs font-semibold uppercase tracking-wider text-muted">Key quotes</h3>
|
package/dashboard/package.json
CHANGED
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
Binary file
|
package/scripts/dashboard-api.py
CHANGED
|
@@ -451,6 +451,9 @@ def agent_update(agent_id: str, body: dict):
|
|
|
451
451
|
raw["communication"] = comm
|
|
452
452
|
if "linked_personas" in body:
|
|
453
453
|
raw["linked_personas"] = _agent_str_list(body["linked_personas"])
|
|
454
|
+
# PR86d v3.18.0 — Markdown bio (long-form free text).
|
|
455
|
+
if "bio_md" in body and isinstance(body["bio_md"], str):
|
|
456
|
+
raw["bio_md"] = body["bio_md"]
|
|
454
457
|
|
|
455
458
|
try:
|
|
456
459
|
tmp = yaml_file.with_suffix(yaml_file.suffix + ".tmp")
|
|
@@ -1101,6 +1104,7 @@ def persona_update(persona_id: str, body: dict):
|
|
|
1101
1104
|
communication=PersonaCommunication(
|
|
1102
1105
|
**(merged.get("communication", {}) or {}),
|
|
1103
1106
|
),
|
|
1107
|
+
bio_md=merged.get("bio_md", "") or "",
|
|
1104
1108
|
created_at=merged.get("created_at", ""),
|
|
1105
1109
|
)
|
|
1106
1110
|
|