mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-21 11:26:41 +02:00
feat(templates): generalise to WorkbenchTemplate + ship Calmness pilot (T1)
First pass of the workbench-templates plan (docs/plans/workbench-
templates.md) — templates are no longer agent-centric but a general
"starter kit" bundle: optional agent + optional scene + optional
missions + optional per-module seeds. Pilot non-AI template "Calmness"
ships alongside.
Shape generalisation (packages/shared-ai/src/agents/templates/types.ts):
- AgentTemplate renamed to WorkbenchTemplate; all fields now optional
(agent, scene, missions, seeds). Back-compat AgentTemplate alias
kept so research/context/today keep compiling.
- Added `category: 'ai'|'wellness'|'work'|'lifeEvent'|'delight'` +
`icon` (for non-agent templates that have no avatar) + `version`
field (for future update-detection).
- New WorkbenchTemplateSeedItem shape: `{stableId?, data: unknown}`.
Module-specific seed payloads are typed at the handler side.
- Existing three AI templates nachgezogen: category='ai' (or
'delight' for today-agent), icon, version='1'.
Seed infrastructure:
- apps/mana/apps/web/src/lib/data/ai/agents/seed-registry.ts — in-
memory handler map keyed by module name; module-local seed.ts files
register themselves at import time.
- apps/mana/apps/web/src/lib/modules/meditate/seed.ts — first handler:
createPreset-based, idempotent via stableId embedded as HTML
comment in the preset description (T1 pragmatism; T2 adds a proper
column on the preset schema).
- data/ai/missions/setup.ts pulls `import '$lib/modules/meditate/seed'`
so the handler is registered before any template is applied.
Applicator upgrades (data/ai/agents/apply-template.ts):
- Agent step now optional — skipped cleanly when template has no
agent part.
- New step 4: seeds. Walks template.seeds, looks up the handler for
each module, aggregates per-item outcomes (created/skipped-exists/
failed) into result.seedOutcomes. Missing handler = warning, not
fatal. Crypto/encryption unchanged — seeds go through the same
module stores that module code already uses.
- Result shape gains `seedOutcomes: Record<string, SeedOutcome[]>`
so the gallery can show "3 new, 1 already there".
Calmness pilot (packages/shared-ai/src/agents/templates/calmness.ts):
- category='wellness', NO agent, scene with meditate/mood/journal/
sleep apps, two meditate preset seeds:
* 4-7-8 Atmung (breathing preset)
* Body-Scan 10min (bodyscan preset with 9 scan steps)
- Each seed has a stableId so re-apply is idempotent.
Gallery updates (routes/(app)/agents/templates/+page.svelte):
- Card avatar falls back to t.icon when no agent. "Agent" chip shows
only for agent-templates; "N Seeds" chip shows for templates with
seeds.
- Detail header shows "Workbench-Setup ohne AI-Agent" when no agent.
- New "Seeds" preview section: lists per-module counts + item names.
- Options section gains a "Seed-Daten in Module einpflegen" checkbox.
- Success panel shows seed summary: "3 Seeds neu, 1 bereits
vorhanden".
Tests: shared-ai 26/26, webapp svelte-check 0 errors, 0 warnings.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a524997a2f
commit
a08e45ca16
14 changed files with 887 additions and 119 deletions
|
|
@ -2,6 +2,13 @@ export type { Agent, AgentState } from './types';
|
|||
export { DEFAULT_AGENT_ID, DEFAULT_AGENT_NAME } from './types';
|
||||
|
||||
export type {
|
||||
WorkbenchTemplate,
|
||||
WorkbenchTemplateAgentPart,
|
||||
WorkbenchTemplateScenePart,
|
||||
WorkbenchTemplateSceneApp,
|
||||
WorkbenchTemplateMissionPart,
|
||||
WorkbenchTemplateSeedItem,
|
||||
WorkbenchTemplateCategory,
|
||||
AgentTemplate,
|
||||
AgentTemplateAgentPart,
|
||||
AgentTemplateScenePart,
|
||||
|
|
|
|||
72
packages/shared-ai/src/agents/templates/calmness.ts
Normal file
72
packages/shared-ai/src/agents/templates/calmness.ts
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import type { WorkbenchTemplate } from './types';
|
||||
|
||||
/**
|
||||
* Calmness — first non-AI workbench template.
|
||||
*
|
||||
* Legt eine Scene fürs Runterkommen an und seed-ed zwei Einstiegs-
|
||||
* Meditationen ins Meditate-Modul. Kein Agent, keine Mission — dieses
|
||||
* Template ist "Infrastruktur für Ruhe", keine Automation.
|
||||
*
|
||||
* Dient in Phase T1 des Workbench-Templates-Plans auch als Pilot-
|
||||
* Template dafür wie nicht-AI-Templates aussehen. Folgende Templates
|
||||
* (Fitness, Deep Work, …) nutzen denselben Shape.
|
||||
*/
|
||||
|
||||
export const calmnessTemplate: WorkbenchTemplate = {
|
||||
id: 'calmness',
|
||||
version: '1',
|
||||
label: 'Calmness',
|
||||
icon: '🧘',
|
||||
tagline: 'Atem, Stille, ruhige Momente',
|
||||
description: `Ein Workbench-Setup für Stille-Momente. Legt dir eine Scene mit den Modulen Meditate, Mood, Journal und Sleep an und seed-et zwei Einstiegs-Meditationen — mehr brauchst du nicht um anzufangen.
|
||||
|
||||
Kein AI-Agent. Du meditierst, nicht dein Computer.`,
|
||||
category: 'wellness',
|
||||
color: '#8B5CF6',
|
||||
scene: {
|
||||
name: 'Calmness',
|
||||
description: 'Ruhe, Atem, Stille',
|
||||
openApps: [
|
||||
{ appId: 'meditate', widthPx: 540 },
|
||||
{ appId: 'mood', widthPx: 340 },
|
||||
{ appId: 'journal', widthPx: 440 },
|
||||
{ appId: 'sleep', widthPx: 340 },
|
||||
],
|
||||
},
|
||||
seeds: {
|
||||
meditate: [
|
||||
{
|
||||
stableId: 'template-calmness:preset:4-7-8',
|
||||
data: {
|
||||
name: '4-7-8 Atmung',
|
||||
description:
|
||||
'Beruhigende Atemtechnik. Einatmen 4 Sekunden, halten 7 Sekunden, ausatmen 8 Sekunden. Gut für abends oder bei Unruhe.',
|
||||
category: 'breathing',
|
||||
breathPattern: { inhale: 4, hold: 7, exhale: 8, rest: 0 },
|
||||
defaultDurationSec: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
stableId: 'template-calmness:preset:bodyscan-10',
|
||||
data: {
|
||||
name: 'Body-Scan 10min',
|
||||
description:
|
||||
'Sanfte Aufmerksamkeits-Wanderung durch den Körper — von den Füßen bis zum Scheitel.',
|
||||
category: 'bodyscan',
|
||||
bodyScanSteps: [
|
||||
'Spüre deine Füße',
|
||||
'Spüre deine Beine',
|
||||
'Spüre dein Becken',
|
||||
'Spüre deinen Bauch',
|
||||
'Spüre deine Brust',
|
||||
'Spüre deine Arme',
|
||||
'Spüre deinen Nacken',
|
||||
'Spüre deinen Kopf',
|
||||
'Spüre deinen ganzen Körper',
|
||||
],
|
||||
defaultDurationSec: 600,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
@ -21,6 +21,8 @@ const CONTEXT_POLICY: AiPolicy = {
|
|||
|
||||
export const contextTemplate: AgentTemplate = {
|
||||
id: 'context',
|
||||
version: '1',
|
||||
icon: '🧭',
|
||||
label: 'Kontext-Agent',
|
||||
tagline: 'Lernt dich kennen, damit andere Agents besser arbeiten',
|
||||
description: `Der Agent fragt dich gezielt Fragen und destilliert die Antworten
|
||||
|
|
@ -35,7 +37,7 @@ Was er tut:
|
|||
3. Verdichtet deine Antworten zu einem strukturierten Kontext-Update (als Vorschlag)
|
||||
|
||||
Alles läuft als Vorschlag — du bestätigst welche Version deines Profils gespeichert wird.`,
|
||||
category: 'context',
|
||||
category: 'ai',
|
||||
color: '#D946EF',
|
||||
agent: {
|
||||
name: 'Kontext-Agent',
|
||||
|
|
|
|||
|
|
@ -10,8 +10,18 @@
|
|||
import { researchTemplate } from './research';
|
||||
import { contextTemplate } from './context';
|
||||
import { todayTemplate } from './today';
|
||||
import { calmnessTemplate } from './calmness';
|
||||
|
||||
export type {
|
||||
// Generalised names (T1 of workbench-templates plan):
|
||||
WorkbenchTemplate,
|
||||
WorkbenchTemplateAgentPart,
|
||||
WorkbenchTemplateScenePart,
|
||||
WorkbenchTemplateSceneApp,
|
||||
WorkbenchTemplateMissionPart,
|
||||
WorkbenchTemplateSeedItem,
|
||||
WorkbenchTemplateCategory,
|
||||
// Pre-T1 aliases:
|
||||
AgentTemplate,
|
||||
AgentTemplateAgentPart,
|
||||
AgentTemplateScenePart,
|
||||
|
|
@ -19,9 +29,14 @@ export type {
|
|||
AgentTemplateMissionPart,
|
||||
} from './types';
|
||||
|
||||
export const ALL_TEMPLATES = [researchTemplate, contextTemplate, todayTemplate] as const;
|
||||
export const ALL_TEMPLATES = [
|
||||
researchTemplate,
|
||||
contextTemplate,
|
||||
todayTemplate,
|
||||
calmnessTemplate,
|
||||
] as const;
|
||||
|
||||
export { researchTemplate, contextTemplate, todayTemplate };
|
||||
export { researchTemplate, contextTemplate, todayTemplate, calmnessTemplate };
|
||||
|
||||
/** Lookup helper — returns the template matching the given id, or
|
||||
* undefined. Useful for deep-links `/agents/templates?pick=research`. */
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ const RESEARCH_POLICY: AiPolicy = {
|
|||
|
||||
export const researchTemplate: AgentTemplate = {
|
||||
id: 'research',
|
||||
version: '1',
|
||||
icon: '🔍',
|
||||
label: 'Recherche-Agent',
|
||||
tagline: 'Liest Quellen, schreibt Notizen, destilliert einen Bericht',
|
||||
description: `Gib dem Agent ein Thema und eine Liste von Quellen-URLs. Er:
|
||||
|
|
@ -32,7 +34,7 @@ export const researchTemplate: AgentTemplate = {
|
|||
4. Verlinkt im Bericht zurück auf die Quellen-Notizen
|
||||
|
||||
Jede Notiz wird als Vorschlag angelegt — du bestätigst was wirklich gespeichert wird.`,
|
||||
category: 'research',
|
||||
category: 'ai',
|
||||
color: '#0EA5E9',
|
||||
agent: {
|
||||
name: 'Recherche-Agent',
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ const TODAY_POLICY: AiPolicy = {
|
|||
|
||||
export const todayTemplate: AgentTemplate = {
|
||||
id: 'today',
|
||||
version: '1',
|
||||
icon: '🌅',
|
||||
label: 'Today-Agent',
|
||||
tagline: 'Jeden Tag ein Gedicht über das was heute besonderes passierte',
|
||||
description: `Der Agent recherchiert täglich (morgens um 7 Uhr) was an diesem
|
||||
|
|
@ -39,7 +41,7 @@ Was er tut:
|
|||
3. Wählt ein Thema das ihn (oder dich) inspiriert
|
||||
4. Schreibt ein kurzes Gedicht (4-8 Zeilen, deutsch)
|
||||
5. Schlägt eine Journal-Notiz vor mit Titel "Heute — [Datum]"`,
|
||||
category: 'today',
|
||||
category: 'delight',
|
||||
color: '#F97316',
|
||||
agent: {
|
||||
name: 'Today-Agent',
|
||||
|
|
|
|||
|
|
@ -1,84 +1,106 @@
|
|||
/**
|
||||
* Agent-Template shape — a bundle of (agent config, optional scene
|
||||
* layout, optional starter missions) that the webapp applies as a
|
||||
* single unit when the user picks it from the template gallery.
|
||||
* Workbench-Template shape — a bundle of (optional agent config,
|
||||
* optional scene layout, optional starter missions, optional
|
||||
* per-module seed data) that the webapp applies as a single unit
|
||||
* when the user picks it from the /agents/templates gallery.
|
||||
*
|
||||
* Templates are pure data: no runtime imports, no side effects, no
|
||||
* references to Dexie / Svelte. The webapp's `apply-template.ts`
|
||||
* orchestrator is the only code that turns a template into concrete
|
||||
* records. This keeps the templates trivial to author (drop a file
|
||||
* next to this one) and keeps shared-ai dependency-free.
|
||||
* records. This keeps templates trivial to author (drop a file next
|
||||
* to the existing ones) and keeps shared-ai dependency-free.
|
||||
*
|
||||
* Originally named `AgentTemplate` (shipped in Phase 5 of the
|
||||
* Multi-Agent Workbench). Generalised in T1 of the Workbench-Templates
|
||||
* plan (docs/plans/workbench-templates.md) so templates can exist
|
||||
* WITHOUT an agent (e.g. a Calmness wellness starter-kit).
|
||||
*/
|
||||
|
||||
import type { AiPolicy } from '../../policy/types';
|
||||
import type { MissionCadence, MissionInputRef } from '../../missions/types';
|
||||
|
||||
export interface AgentTemplateAgentPart {
|
||||
/** Display name — the user can rename after creation. Must be unique
|
||||
* at apply-time; the orchestrator deduplicates via `createAgent`. */
|
||||
export type WorkbenchTemplateCategory = 'ai' | 'wellness' | 'work' | 'lifeEvent' | 'delight';
|
||||
|
||||
export interface WorkbenchTemplateAgentPart {
|
||||
name: string;
|
||||
/** Emoji or short string. Shown on the card + everywhere the agent
|
||||
* appears in UI. */
|
||||
avatar: string;
|
||||
/** Short user-facing description ("what this agent does for you"). */
|
||||
role: string;
|
||||
/** Optional pre-filled systemPrompt. Encrypted at rest. */
|
||||
systemPrompt?: string;
|
||||
/** Optional pre-filled memory. Encrypted at rest. */
|
||||
memory?: string;
|
||||
/** Per-tool + per-module decisions. Templates reuse the DEFAULT_AI_POLICY
|
||||
* and layer tweaks on top. Undefined → DEFAULT_AI_POLICY. */
|
||||
policy?: AiPolicy;
|
||||
/** Optional budget; undefined = no daily cap. */
|
||||
maxTokensPerDay?: number;
|
||||
/** Default 1 (serial). */
|
||||
maxConcurrentMissions?: number;
|
||||
}
|
||||
|
||||
export interface AgentTemplateSceneApp {
|
||||
export interface WorkbenchTemplateSceneApp {
|
||||
readonly appId: string;
|
||||
readonly widthPx?: number;
|
||||
readonly maximized?: boolean;
|
||||
}
|
||||
|
||||
export interface AgentTemplateScenePart {
|
||||
/** Display name for the scene tab. */
|
||||
export interface WorkbenchTemplateScenePart {
|
||||
name: string;
|
||||
description?: string;
|
||||
openApps: readonly AgentTemplateSceneApp[];
|
||||
openApps: readonly WorkbenchTemplateSceneApp[];
|
||||
}
|
||||
|
||||
export interface AgentTemplateMissionPart {
|
||||
export interface WorkbenchTemplateMissionPart {
|
||||
title: string;
|
||||
objective: string;
|
||||
conceptMarkdown: string;
|
||||
cadence: MissionCadence;
|
||||
inputs?: readonly MissionInputRef[];
|
||||
/** Whether the mission should be immediately active. Templates
|
||||
* default to `paused` so the user has to hit Play — avoids
|
||||
* surprise autonomous work on first use. */
|
||||
startPaused?: boolean;
|
||||
}
|
||||
|
||||
export interface AgentTemplate {
|
||||
/** Stable id, used for analytics + "this template was applied" detection. */
|
||||
id: string;
|
||||
/** Short display label for the gallery card. */
|
||||
label: string;
|
||||
/** One-line tagline under the label. */
|
||||
tagline: string;
|
||||
/** Longer body for the card's detail pane. Can be markdown. */
|
||||
description: string;
|
||||
/** Category / tag for grouping in the gallery. */
|
||||
category: 'research' | 'context' | 'today' | 'custom';
|
||||
/** Accent color for the card. */
|
||||
color: string;
|
||||
|
||||
agent: AgentTemplateAgentPart;
|
||||
/** Optional — when absent, no scene is created. When present, the
|
||||
* orchestrator creates a scene pre-populated with these apps. */
|
||||
scene?: AgentTemplateScenePart;
|
||||
/** Optional starter missions. Each defaults to `startPaused: true`
|
||||
* so autonomous work doesn't start without explicit user consent. */
|
||||
missions?: readonly AgentTemplateMissionPart[];
|
||||
/**
|
||||
* One seeded record in a module. The Applicator passes these to the
|
||||
* module's SeedHandler by name; the handler unpacks `data` according
|
||||
* to its own schema.
|
||||
*/
|
||||
export interface WorkbenchTemplateSeedItem {
|
||||
/** Stable identifier for idempotent re-apply. When set, the handler
|
||||
* looks up an existing record with the same stableId and skips
|
||||
* re-creation. When unset, a fresh record is created on every
|
||||
* apply (UUID-random). */
|
||||
readonly stableId?: string;
|
||||
/** Module-specific payload. The seed handler for the matching
|
||||
* module name knows the shape. Typed as `unknown` here so shared-ai
|
||||
* doesn't import the webapp's module types. */
|
||||
readonly data: unknown;
|
||||
}
|
||||
|
||||
export interface WorkbenchTemplate {
|
||||
readonly id: string;
|
||||
/** Schema/content version stamped on the scene when applied — used
|
||||
* later for update-detection. Start at '1'. */
|
||||
readonly version: string;
|
||||
readonly label: string;
|
||||
readonly tagline: string;
|
||||
readonly description: string;
|
||||
readonly category: WorkbenchTemplateCategory;
|
||||
readonly color: string;
|
||||
/** Icon emoji for the gallery card when no agent avatar is present. */
|
||||
readonly icon: string;
|
||||
|
||||
// All component parts are optional — a template can be agent-only,
|
||||
// scene-only, seeds-only, or any combination.
|
||||
readonly agent?: WorkbenchTemplateAgentPart;
|
||||
readonly scene?: WorkbenchTemplateScenePart;
|
||||
readonly missions?: readonly WorkbenchTemplateMissionPart[];
|
||||
/** Module-name → seed items for that module. Keys match module
|
||||
* names from apps/mana/apps/web/src/lib/modules/*. Unknown keys
|
||||
* are reported as warnings by the applicator, not fatal. */
|
||||
readonly seeds?: Readonly<Record<string, readonly WorkbenchTemplateSeedItem[]>>;
|
||||
}
|
||||
|
||||
// ─── Backward-compat aliases ─────────────────────────────────
|
||||
// Pre-T1 name. Existing templates (research/context/today) typed
|
||||
// themselves as `AgentTemplate`; keep the aliases so nothing breaks.
|
||||
// New templates should use `WorkbenchTemplate` directly.
|
||||
|
||||
export type AgentTemplate = WorkbenchTemplate;
|
||||
export type AgentTemplateAgentPart = WorkbenchTemplateAgentPart;
|
||||
export type AgentTemplateScenePart = WorkbenchTemplateScenePart;
|
||||
export type AgentTemplateSceneApp = WorkbenchTemplateSceneApp;
|
||||
export type AgentTemplateMissionPart = WorkbenchTemplateMissionPart;
|
||||
|
|
|
|||
|
|
@ -83,5 +83,12 @@ export type {
|
|||
AgentTemplateScenePart,
|
||||
AgentTemplateSceneApp,
|
||||
AgentTemplateMissionPart,
|
||||
WorkbenchTemplate,
|
||||
WorkbenchTemplateAgentPart,
|
||||
WorkbenchTemplateScenePart,
|
||||
WorkbenchTemplateSceneApp,
|
||||
WorkbenchTemplateMissionPart,
|
||||
WorkbenchTemplateSeedItem,
|
||||
WorkbenchTemplateCategory,
|
||||
} from './agents';
|
||||
export { DEFAULT_AGENT_ID, DEFAULT_AGENT_NAME, ALL_TEMPLATES, getTemplateById } from './agents';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue