arkaos 3.42.0 → 3.44.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.42.0
1
+ 3.44.0
@@ -0,0 +1,176 @@
1
+ """Curated persona archetype templates (PR93b v3.44.0).
2
+
3
+ These are generic, public-domain starter profiles operators can pick
4
+ from when creating a new persona without a real source. They populate
5
+ the PersonaWizard description field plus surface defaults for MBTI,
6
+ DISC, and Enneagram so the LLM has less guesswork to do.
7
+
8
+ Add new archetypes by appending a dict to `ARCHETYPES`. The shape is
9
+ ``{id, name, title, tagline, mbti, disc, enneagram, big_five,
10
+ description}``.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+
16
+ ARCHETYPES: list[dict] = [
17
+ {
18
+ "id": "the-coach",
19
+ "name": "The Coach",
20
+ "title": "Supportive accountability partner",
21
+ "tagline": "Helps you see what you can't see — and keeps you honest.",
22
+ "mbti": "INFJ",
23
+ "disc": {"primary": "S", "secondary": "I"},
24
+ "enneagram": {"type": 2, "wing": 1},
25
+ "big_five": {
26
+ "openness": 75, "conscientiousness": 70,
27
+ "extraversion": 55, "agreeableness": 85, "neuroticism": 35,
28
+ },
29
+ "description": (
30
+ "An empathetic operator coach who listens first, mirrors the "
31
+ "person's own words back, and asks the question they've been "
32
+ "avoiding. Warm, patient, slow to advise. Allergic to "
33
+ "performance theatre and motivational fluff."
34
+ ),
35
+ },
36
+ {
37
+ "id": "the-skeptic",
38
+ "name": "The Skeptic",
39
+ "title": "Evidence-driven dissenter",
40
+ "tagline": "If the data doesn't back it, it doesn't ship.",
41
+ "mbti": "INTJ",
42
+ "disc": {"primary": "C", "secondary": "D"},
43
+ "enneagram": {"type": 5, "wing": 6},
44
+ "big_five": {
45
+ "openness": 80, "conscientiousness": 85,
46
+ "extraversion": 35, "agreeableness": 40, "neuroticism": 30,
47
+ },
48
+ "description": (
49
+ "A research-heavy contrarian who cares about evidence more "
50
+ "than consensus. Asks for sources, surfaces the inconvenient "
51
+ "graph, refuses to round numbers. Allergic to hand-waving "
52
+ "and vibes-based decision-making."
53
+ ),
54
+ },
55
+ {
56
+ "id": "the-founder",
57
+ "name": "The Founder",
58
+ "title": "Bias-to-action operator",
59
+ "tagline": "Speed beats polish — ship, then iterate.",
60
+ "mbti": "ENTJ",
61
+ "disc": {"primary": "D", "secondary": "I"},
62
+ "enneagram": {"type": 3, "wing": 8},
63
+ "big_five": {
64
+ "openness": 80, "conscientiousness": 70,
65
+ "extraversion": 75, "agreeableness": 45, "neuroticism": 30,
66
+ },
67
+ "description": (
68
+ "Vision-driven, urgency-first. Will trade perfection for "
69
+ "shipping today. Loves frameworks but doesn't worship them. "
70
+ "Speaks in outcomes, not effort. Allergic to meetings that "
71
+ "could have been a message."
72
+ ),
73
+ },
74
+ {
75
+ "id": "the-operator",
76
+ "name": "The Operator",
77
+ "title": "Process-perfection executor",
78
+ "tagline": "Show me the system; the result follows.",
79
+ "mbti": "ESTJ",
80
+ "disc": {"primary": "S", "secondary": "C"},
81
+ "enneagram": {"type": 1, "wing": 2},
82
+ "big_five": {
83
+ "openness": 55, "conscientiousness": 90,
84
+ "extraversion": 60, "agreeableness": 60, "neuroticism": 30,
85
+ },
86
+ "description": (
87
+ "Process-obsessed implementor. Builds SOPs, eliminates "
88
+ "ambiguity, measures everything. Calm under chaos, "
89
+ "demanding under sloppy execution. Allergic to "
90
+ "improvisation as a strategy."
91
+ ),
92
+ },
93
+ {
94
+ "id": "the-strategist",
95
+ "name": "The Strategist",
96
+ "title": "Frameworks-first analyst",
97
+ "tagline": "Map the terrain before you pick the route.",
98
+ "mbti": "INTP",
99
+ "disc": {"primary": "C", "secondary": "I"},
100
+ "enneagram": {"type": 5, "wing": 4},
101
+ "big_five": {
102
+ "openness": 90, "conscientiousness": 70,
103
+ "extraversion": 40, "agreeableness": 55, "neuroticism": 30,
104
+ },
105
+ "description": (
106
+ "Pattern-recogniser who reaches for Porter, Wardley, and "
107
+ "Christensen before tactics. Lays out the choice tree, "
108
+ "shows the second-order effects, then steps back. Allergic "
109
+ "to tactics dressed up as strategy."
110
+ ),
111
+ },
112
+ {
113
+ "id": "the-storyteller",
114
+ "name": "The Storyteller",
115
+ "title": "Narrative-shaping communicator",
116
+ "tagline": "The story is the strategy.",
117
+ "mbti": "ENFP",
118
+ "disc": {"primary": "I", "secondary": "S"},
119
+ "enneagram": {"type": 4, "wing": 3},
120
+ "big_five": {
121
+ "openness": 90, "conscientiousness": 55,
122
+ "extraversion": 80, "agreeableness": 70, "neuroticism": 40,
123
+ },
124
+ "description": (
125
+ "Finds the through-line, names the villain, picks the "
126
+ "hero. Treats every artifact as a chance to land the "
127
+ "emotional beat. Allergic to dry feature lists and "
128
+ "jargon-stuffed updates."
129
+ ),
130
+ },
131
+ {
132
+ "id": "the-architect",
133
+ "name": "The Architect",
134
+ "title": "Systems-thinking abstraction lover",
135
+ "tagline": "Build it so the next change is easy.",
136
+ "mbti": "INTJ",
137
+ "disc": {"primary": "C", "secondary": "D"},
138
+ "enneagram": {"type": 5, "wing": 1},
139
+ "big_five": {
140
+ "openness": 85, "conscientiousness": 80,
141
+ "extraversion": 40, "agreeableness": 50, "neuroticism": 30,
142
+ },
143
+ "description": (
144
+ "Designs for the second migration. Treats interfaces as "
145
+ "contracts, considers blast radius before keystrokes, "
146
+ "documents invariants. Allergic to clever shortcuts that "
147
+ "trade future cost for present convenience."
148
+ ),
149
+ },
150
+ {
151
+ "id": "the-negotiator",
152
+ "name": "The Negotiator",
153
+ "title": "Leverage-aware deal-maker",
154
+ "tagline": "Whoever frames the problem owns the outcome.",
155
+ "mbti": "ENTP",
156
+ "disc": {"primary": "I", "secondary": "D"},
157
+ "enneagram": {"type": 7, "wing": 8},
158
+ "big_five": {
159
+ "openness": 85, "conscientiousness": 60,
160
+ "extraversion": 80, "agreeableness": 55, "neuroticism": 30,
161
+ },
162
+ "description": (
163
+ "Reads the room, names the unstated stakes, reshapes the "
164
+ "default. Comfortable with silence. Treats every "
165
+ "objection as new information. Allergic to splitting the "
166
+ "difference too early."
167
+ ),
168
+ },
169
+ ]
170
+
171
+
172
+ def get_archetype(archetype_id: str) -> dict | None:
173
+ for a in ARCHETYPES:
174
+ if a["id"] == archetype_id:
175
+ return a
176
+ return None
@@ -13,7 +13,7 @@ import type { Persona } from '~/types'
13
13
  //
14
14
  // The wizard NEVER auto-saves — every transition is operator-confirmed.
15
15
 
16
- const { apiBase } = useApi()
16
+ const { apiBase, fetchApi } = useApi()
17
17
  const toast = useToast()
18
18
 
19
19
  const emit = defineEmits<{
@@ -43,6 +43,26 @@ const mode = ref<Mode>('sources')
43
43
  const description = ref('')
44
44
  const descriptionLength = computed(() => description.value.trim().length)
45
45
 
46
+ // PR93b v3.44.0 — archetype templates that pre-fill description + name.
47
+ interface Archetype {
48
+ id: string
49
+ name: string
50
+ title: string
51
+ tagline: string
52
+ description: string
53
+ }
54
+ const { data: archetypeData } = fetchApi<{ archetypes: Archetype[] }>(
55
+ '/api/personas/archetypes',
56
+ )
57
+ const archetypes = computed<Archetype[]>(() => archetypeData.value?.archetypes ?? [])
58
+
59
+ function applyArchetype(arch: Archetype) {
60
+ if (!name.value.trim()) name.value = arch.name
61
+ if (!sourceLabel.value.trim()) sourceLabel.value = arch.title
62
+ description.value = arch.description
63
+ mode.value = 'description'
64
+ }
65
+
46
66
  // ─── Step 2 state ────────────────────────────────────────────────────────
47
67
  const ingestJobs = ref<Array<{
48
68
  source: string
@@ -389,10 +409,28 @@ function backToStep1() {
389
409
  label="Description"
390
410
  help="Plain-text description of the person — their style, beliefs, what they do, how they talk. The LLM uses this verbatim. Minimum 20 characters."
391
411
  >
412
+ <template #hint>
413
+ <UDropdownMenu
414
+ v-if="archetypes.length > 0"
415
+ :items="archetypes.map((a) => ({
416
+ label: `${a.name} — ${a.title}`,
417
+ icon: 'i-lucide-sparkles',
418
+ onSelect: () => applyArchetype(a),
419
+ }))"
420
+ >
421
+ <UButton
422
+ label="Start from archetype"
423
+ icon="i-lucide-sparkles"
424
+ variant="ghost"
425
+ size="xs"
426
+ trailing-icon="i-lucide-chevron-down"
427
+ />
428
+ </UDropdownMenu>
429
+ </template>
392
430
  <UTextarea
393
431
  v-model="description"
394
432
  :rows="6"
395
- placeholder="A direct-response copywriter who treats offers as the only true growth lever. Punchy, allergic to fluff. Loves Hormozi-style hooks."
433
+ placeholder="A direct-response copywriter who treats offers as the only true growth lever. Punchy, allergic to fluff."
396
434
  class="w-full"
397
435
  />
398
436
  </UFormField>
@@ -13,6 +13,7 @@ interface WorkflowPhase {
13
13
  description: string
14
14
  gate_type: string
15
15
  agent_count: number
16
+ agent_ids?: string[]
16
17
  }
17
18
 
18
19
  interface Workflow {
@@ -268,16 +269,22 @@ const columns: TableColumn<Workflow>[] = [
268
269
  variant="subtle"
269
270
  size="xs"
270
271
  />
271
- <UBadge
272
- v-if="ph.agent_count > 0"
273
- :label="`${ph.agent_count} agent${ph.agent_count === 1 ? '' : 's'}`"
274
- variant="outline"
275
- size="xs"
276
- />
277
272
  </div>
278
273
  <p v-if="ph.description" class="text-xs text-muted mt-1">
279
274
  {{ ph.description }}
280
275
  </p>
276
+ <!-- PR93a v3.43.0 — clickable agent badges -->
277
+ <div v-if="ph.agent_ids && ph.agent_ids.length > 0" class="flex flex-wrap gap-1 mt-2">
278
+ <NuxtLink
279
+ v-for="aid in ph.agent_ids"
280
+ :key="aid"
281
+ :to="`/agents/${aid}`"
282
+ class="inline-flex items-center gap-1 rounded-md border border-default px-1.5 py-0.5 text-[10px] font-mono hover:border-primary/40 hover:text-primary transition-colors"
283
+ >
284
+ <UIcon name="i-lucide-user" class="size-2.5" />
285
+ {{ aid }}
286
+ </NuxtLink>
287
+ </div>
281
288
  </div>
282
289
  </li>
283
290
  </ol>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkaos",
3
- "version": "3.42.0",
3
+ "version": "3.44.0",
4
4
  "description": "The Operating System for AI Agent Teams",
5
5
  "type": "module",
6
6
  "bin": {
package/pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "arkaos-core"
3
- version = "3.42.0"
3
+ version = "3.44.0"
4
4
  description = "Core engine for ArkaOS — The Operating System for AI Agent Teams"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -322,6 +322,17 @@ def agent_activity_strip(agent_id: str, period: str = "month"):
322
322
  }
323
323
 
324
324
 
325
+ @app.get("/api/personas/archetypes")
326
+ def personas_archetypes():
327
+ """PR93b v3.44.0 — list curated persona archetype templates.
328
+
329
+ Used by PersonaWizard step 1 to seed the description field + DNA
330
+ defaults when the operator picks "Start from archetype".
331
+ """
332
+ from core.personas.archetypes import ARCHETYPES
333
+ return {"archetypes": ARCHETYPES, "total": len(ARCHETYPES)}
334
+
335
+
325
336
  @app.get("/api/personas/export-all.zip")
326
337
  def personas_export_all():
327
338
  """PR92a v3.39.0 — stream every persona as Markdown inside a ZIP.
@@ -1918,21 +1929,30 @@ def workflows_list():
1918
1929
 
1919
1930
 
1920
1931
  def _summarise_phases(phases: list) -> list[dict]:
1921
- """PR91c v3.37.0 — distil each phase down to what the flow stepper needs."""
1932
+ """PR91c v3.37.0 — distil each phase down to what the flow stepper needs.
1933
+
1934
+ PR93a v3.43.0 — also surfaces the explicit ``agent_ids`` so the UI
1935
+ can render them as clickable badges.
1936
+ """
1922
1937
  out: list[dict] = []
1923
1938
  for p in phases:
1924
1939
  if not isinstance(p, dict):
1925
1940
  continue
1926
1941
  gate = p.get("gate") if isinstance(p.get("gate"), dict) else {}
1927
1942
  agents = p.get("agents") if isinstance(p.get("agents"), list) else []
1943
+ agent_ids: list[str] = []
1944
+ for a in agents:
1945
+ if isinstance(a, dict):
1946
+ aid = a.get("agent_id")
1947
+ if aid:
1948
+ agent_ids.append(str(aid))
1928
1949
  out.append({
1929
1950
  "id": str(p.get("id") or ""),
1930
1951
  "name": str(p.get("name") or ""),
1931
1952
  "description": str(p.get("description") or ""),
1932
1953
  "gate_type": str(gate.get("type") or ""),
1933
- "agent_count": sum(
1934
- 1 for a in agents if isinstance(a, dict) and a.get("agent_id")
1935
- ),
1954
+ "agent_count": len(agent_ids),
1955
+ "agent_ids": agent_ids,
1936
1956
  })
1937
1957
  return out
1938
1958