arkaos 3.65.0 → 3.66.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
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.66.0
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// PR98d v3.66.0 — Agent dependency graph.
|
|
3
|
+
//
|
|
4
|
+
// Shows the current agent in the middle, its linked personas above,
|
|
5
|
+
// and other agents that link to those same personas (siblings) below.
|
|
6
|
+
// Pure SVG, no graph lib. Frontend-only — reuses existing endpoints.
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
agentId: string
|
|
10
|
+
agentName: string
|
|
11
|
+
linkedPersonas: string[]
|
|
12
|
+
}
|
|
13
|
+
const props = defineProps<Props>()
|
|
14
|
+
|
|
15
|
+
const { fetchApi } = useApi()
|
|
16
|
+
|
|
17
|
+
// /api/personas/usage returns the reverse lookup we need.
|
|
18
|
+
const { data: usageData } = fetchApi<{
|
|
19
|
+
by_persona: Record<string, { agent_count: number, agent_ids: string[] }>
|
|
20
|
+
}>('/api/personas/usage')
|
|
21
|
+
|
|
22
|
+
// /api/personas for resolving persona names.
|
|
23
|
+
const { data: personasData } = fetchApi<{
|
|
24
|
+
personas: Array<{ id: string, name: string }>
|
|
25
|
+
}>('/api/personas')
|
|
26
|
+
|
|
27
|
+
function personaName(id: string): string {
|
|
28
|
+
return personasData.value?.personas?.find((p) => p.id === id)?.name ?? id
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const siblings = computed<string[]>(() => {
|
|
32
|
+
const ids = new Set<string>()
|
|
33
|
+
const usage = usageData.value?.by_persona ?? {}
|
|
34
|
+
for (const pid of props.linkedPersonas) {
|
|
35
|
+
for (const aid of (usage[pid]?.agent_ids ?? [])) {
|
|
36
|
+
if (aid && aid !== props.agentId) ids.add(aid)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return Array.from(ids).slice(0, 6)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
// Layout constants — keep tight so the graph fits the hero card.
|
|
43
|
+
const WIDTH = 700
|
|
44
|
+
const HEIGHT = 220
|
|
45
|
+
const CENTER_X = WIDTH / 2
|
|
46
|
+
const CENTER_Y = HEIGHT / 2
|
|
47
|
+
const NODE_W = 110
|
|
48
|
+
const NODE_H = 32
|
|
49
|
+
const NODE_RX = 8
|
|
50
|
+
|
|
51
|
+
function distributeX(count: number, idx: number): number {
|
|
52
|
+
if (count === 1) return CENTER_X
|
|
53
|
+
const span = Math.min(WIDTH - 80, count * (NODE_W + 20))
|
|
54
|
+
const start = (WIDTH - span) / 2 + NODE_W / 2
|
|
55
|
+
const step = count > 1 ? (span - NODE_W) / (count - 1) : 0
|
|
56
|
+
return start + idx * step
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const personaPositions = computed(() =>
|
|
60
|
+
props.linkedPersonas.map((id, i) => ({
|
|
61
|
+
id,
|
|
62
|
+
x: distributeX(props.linkedPersonas.length, i),
|
|
63
|
+
y: 32,
|
|
64
|
+
})),
|
|
65
|
+
)
|
|
66
|
+
const siblingPositions = computed(() =>
|
|
67
|
+
siblings.value.map((id, i) => ({
|
|
68
|
+
id,
|
|
69
|
+
x: distributeX(siblings.value.length, i),
|
|
70
|
+
y: HEIGHT - 32,
|
|
71
|
+
})),
|
|
72
|
+
)
|
|
73
|
+
</script>
|
|
74
|
+
|
|
75
|
+
<template>
|
|
76
|
+
<div
|
|
77
|
+
v-if="props.linkedPersonas.length > 0 || siblings.length > 0"
|
|
78
|
+
class="rounded-xl border border-default bg-elevated/10 p-5"
|
|
79
|
+
>
|
|
80
|
+
<h3 class="text-sm font-semibold uppercase tracking-wide text-muted mb-3">
|
|
81
|
+
Dependency graph
|
|
82
|
+
</h3>
|
|
83
|
+
<svg
|
|
84
|
+
:viewBox="`0 0 ${WIDTH} ${HEIGHT}`"
|
|
85
|
+
class="w-full"
|
|
86
|
+
preserveAspectRatio="xMidYMid meet"
|
|
87
|
+
>
|
|
88
|
+
<!-- Connector lines (personas → center) -->
|
|
89
|
+
<line
|
|
90
|
+
v-for="p in personaPositions"
|
|
91
|
+
:key="`pl-${p.id}`"
|
|
92
|
+
:x1="p.x"
|
|
93
|
+
:y1="p.y + NODE_H / 2"
|
|
94
|
+
:x2="CENTER_X"
|
|
95
|
+
:y2="CENTER_Y - NODE_H / 2"
|
|
96
|
+
class="stroke-default"
|
|
97
|
+
stroke-width="1"
|
|
98
|
+
/>
|
|
99
|
+
<!-- Connector lines (center → siblings) -->
|
|
100
|
+
<line
|
|
101
|
+
v-for="s in siblingPositions"
|
|
102
|
+
:key="`sl-${s.id}`"
|
|
103
|
+
:x1="CENTER_X"
|
|
104
|
+
:y1="CENTER_Y + NODE_H / 2"
|
|
105
|
+
:x2="s.x"
|
|
106
|
+
:y2="s.y - NODE_H / 2"
|
|
107
|
+
class="stroke-default"
|
|
108
|
+
stroke-width="1"
|
|
109
|
+
stroke-dasharray="3,2"
|
|
110
|
+
/>
|
|
111
|
+
|
|
112
|
+
<!-- Persona nodes (top) -->
|
|
113
|
+
<g
|
|
114
|
+
v-for="p in personaPositions"
|
|
115
|
+
:key="`p-${p.id}`"
|
|
116
|
+
>
|
|
117
|
+
<a :href="`/personas/${p.id}`">
|
|
118
|
+
<rect
|
|
119
|
+
:x="p.x - NODE_W / 2"
|
|
120
|
+
:y="p.y - NODE_H / 2"
|
|
121
|
+
:width="NODE_W"
|
|
122
|
+
:height="NODE_H"
|
|
123
|
+
:rx="NODE_RX"
|
|
124
|
+
class="fill-emerald-500/10 stroke-emerald-500/40"
|
|
125
|
+
stroke-width="1"
|
|
126
|
+
/>
|
|
127
|
+
<text
|
|
128
|
+
:x="p.x"
|
|
129
|
+
:y="p.y + 4"
|
|
130
|
+
text-anchor="middle"
|
|
131
|
+
class="fill-emerald-700 dark:fill-emerald-300 text-xs"
|
|
132
|
+
>
|
|
133
|
+
{{ personaName(p.id).slice(0, 14) }}
|
|
134
|
+
</text>
|
|
135
|
+
<title>{{ personaName(p.id) }}</title>
|
|
136
|
+
</a>
|
|
137
|
+
</g>
|
|
138
|
+
|
|
139
|
+
<!-- Centre node: current agent -->
|
|
140
|
+
<g>
|
|
141
|
+
<rect
|
|
142
|
+
:x="CENTER_X - NODE_W / 2 - 10"
|
|
143
|
+
:y="CENTER_Y - NODE_H / 2"
|
|
144
|
+
:width="NODE_W + 20"
|
|
145
|
+
:height="NODE_H"
|
|
146
|
+
:rx="NODE_RX"
|
|
147
|
+
class="fill-primary/15 stroke-primary"
|
|
148
|
+
stroke-width="1.5"
|
|
149
|
+
/>
|
|
150
|
+
<text
|
|
151
|
+
:x="CENTER_X"
|
|
152
|
+
:y="CENTER_Y + 4"
|
|
153
|
+
text-anchor="middle"
|
|
154
|
+
class="fill-primary text-sm font-semibold"
|
|
155
|
+
>
|
|
156
|
+
{{ props.agentName.slice(0, 16) }}
|
|
157
|
+
</text>
|
|
158
|
+
</g>
|
|
159
|
+
|
|
160
|
+
<!-- Sibling agent nodes (bottom) -->
|
|
161
|
+
<g
|
|
162
|
+
v-for="s in siblingPositions"
|
|
163
|
+
:key="`s-${s.id}`"
|
|
164
|
+
>
|
|
165
|
+
<a :href="`/agents/${s.id}`">
|
|
166
|
+
<rect
|
|
167
|
+
:x="s.x - NODE_W / 2"
|
|
168
|
+
:y="s.y - NODE_H / 2"
|
|
169
|
+
:width="NODE_W"
|
|
170
|
+
:height="NODE_H"
|
|
171
|
+
:rx="NODE_RX"
|
|
172
|
+
class="fill-blue-500/10 stroke-blue-500/40"
|
|
173
|
+
stroke-width="1"
|
|
174
|
+
/>
|
|
175
|
+
<text
|
|
176
|
+
:x="s.x"
|
|
177
|
+
:y="s.y + 4"
|
|
178
|
+
text-anchor="middle"
|
|
179
|
+
class="fill-blue-700 dark:fill-blue-300 text-xs"
|
|
180
|
+
>
|
|
181
|
+
{{ s.id.slice(0, 14) }}
|
|
182
|
+
</text>
|
|
183
|
+
<title>{{ s.id }}</title>
|
|
184
|
+
</a>
|
|
185
|
+
</g>
|
|
186
|
+
</svg>
|
|
187
|
+
<p class="text-xs text-muted mt-2 italic">
|
|
188
|
+
Top: linked personas · Centre: this agent · Bottom: siblings (other
|
|
189
|
+
agents linking the same personas)
|
|
190
|
+
</p>
|
|
191
|
+
</div>
|
|
192
|
+
</template>
|
|
@@ -658,6 +658,14 @@ function formatTokens(n: number): string {
|
|
|
658
658
|
</div>
|
|
659
659
|
</section>
|
|
660
660
|
|
|
661
|
+
<!-- ===== DEPENDENCY GRAPH (PR98d) ===== -->
|
|
662
|
+
<AgentDependencyGraph
|
|
663
|
+
v-if="agent.linked_personas && agent.linked_personas.length > 0"
|
|
664
|
+
:agent-id="agent.id"
|
|
665
|
+
:agent-name="agent.name"
|
|
666
|
+
:linked-personas="agent.linked_personas"
|
|
667
|
+
/>
|
|
668
|
+
|
|
661
669
|
<!-- ===== BIO (PR86d) ===== -->
|
|
662
670
|
<section
|
|
663
671
|
v-if="(agent as any).bio_md"
|
package/package.json
CHANGED