/** * Property On — «Teamübersicht»: digitale Mitarbeiter. * * Namensgebung: Der Entitätstyp heisst `TeamAgent`, nicht `Agent`. Im Repo existiert * bereits `PowerOn` (AI-Backend-Proxy) und Claude-Code legt Worktrees unter `agent-*` * ab — ein nackter Typ `Agent` wäre in Suchen praktisch nicht auffindbar. Alle * Satellitentypen tragen deshalb das Präfix `Agent*`; generische Namen wie `Status`, * `Priority` oder `Channel` sind tabu, weil `src/domain/index.ts` per `export *` * bündelt und dort bereits `ReviewStatus`, `SourceType`, `RiskLevel` u. a. liegen. * * Fachliche Wahrheit ist der Agenten-Katalog: Rollen, Personalnummern und * Zuständigkeiten der fünf Kernagenten werden nicht verändert. */ // ── Status & Autonomie ──────────────────────────────────────────────────────── export const AgentStatus = { ACTIVE: 'ACTIVE', BUILDING: 'BUILDING', PAUSED: 'PAUSED', } as const export type AgentStatus = typeof AgentStatus[keyof typeof AgentStatus] export const AgentAutonomyLevel = { AUTONOMOUS: 'AUTONOMOUS', APPROVAL_REQUIRED: 'APPROVAL_REQUIRED', PROPOSAL_ONLY: 'PROPOSAL_ONLY', } as const export type AgentAutonomyLevel = typeof AgentAutonomyLevel[keyof typeof AgentAutonomyLevel] // ── Kanäle ──────────────────────────────────────────────────────────────────── export const AgentChannelType = { EMAIL: 'EMAIL', TEAMS: 'TEAMS', WHATSAPP: 'WHATSAPP', WORKSPACE_CHAT: 'WORKSPACE_CHAT', CALENDAR: 'CALENDAR', WEB_FORM: 'WEB_FORM', PORTAL_LEAD_MAIL: 'PORTAL_LEAD_MAIL', PHONE_VOICE: 'PHONE_VOICE', PHONE_NOTE: 'PHONE_NOTE', AUDIO_OUTPUT: 'AUDIO_OUTPUT', STRUCTURED_MAIL_FALLBACK: 'STRUCTURED_MAIL_FALLBACK', } as const export type AgentChannelType = typeof AgentChannelType[keyof typeof AgentChannelType] export const AgentChannelDirection = { INBOUND: 'INBOUND', OUTBOUND: 'OUTBOUND', BOTH: 'BOTH', } as const export type AgentChannelDirection = typeof AgentChannelDirection[keyof typeof AgentChannelDirection] export const AgentConnectionStatus = { CONNECTED: 'CONNECTED', DISCONNECTED: 'DISCONNECTED', ROADMAP: 'ROADMAP', } as const export type AgentConnectionStatus = typeof AgentConnectionStatus[keyof typeof AgentConnectionStatus] /** Simulierte Kanalkonfiguration — es werden nie echte Zugangsdaten erfasst. */ export interface AgentChannelConfig { displayName: string senderAddress?: string inboxAddress?: string defaultRecipients: string[] autoReplyEnabled: boolean } export interface AgentChannel { id: string type: AgentChannelType direction: AgentChannelDirection description: string status: AgentConnectionStatus enabled: boolean /** Kennzeichnet im Katalog als «optional» geführte Kanäle. */ optional?: boolean config: AgentChannelConfig } // ── Systeme ─────────────────────────────────────────────────────────────────── export const AgentSystemType = { M365_EXCHANGE: 'M365_EXCHANGE', OUTLOOK: 'OUTLOOK', SHAREPOINT: 'SHAREPOINT', ONEDRIVE: 'ONEDRIVE', FILESHARE: 'FILESHARE', DMS: 'DMS', CALENDAR: 'CALENDAR', IMMOTOP2: 'IMMOTOP2', ABACUS_ABAIMMO: 'ABACUS_ABAIMMO', RIMO_R5: 'RIMO_R5', GARAIO_REM: 'GARAIO_REM', CRM: 'CRM', ZEFIX: 'ZEFIX', SHAB: 'SHAB', PUBLIC_WEB: 'PUBLIC_WEB', PORTAL_LEAD_INBOX: 'PORTAL_LEAD_INBOX', WORKSPACE: 'WORKSPACE', } as const export type AgentSystemType = typeof AgentSystemType[keyof typeof AgentSystemType] export const AgentAccessLevel = { READ: 'READ', WRITE: 'WRITE', READ_WRITE: 'READ_WRITE', } as const export type AgentAccessLevel = typeof AgentAccessLevel[keyof typeof AgentAccessLevel] export interface AgentSystem { id: string type: AgentSystemType access: AgentAccessLevel status: AgentConnectionStatus /** * Ob der Mitarbeiter diesen Zugang derzeit nutzt. Optional, weil der Katalog * die Zugänge ohne Schalter führt — fehlt das Feld, gilt der Zugang als aktiv. */ enabled?: boolean /** * Eigener Titel der Quelle (Runde 10, §2.1). Der Katalog benennt seine * Zugänge über `type`; selbst angebundene Quellen haben keinen passenden * Typ und tragen ihren Namen deshalb hier. Fehlt der Titel, gilt das Label * des Typs — so bleiben die Katalogeinträge unverändert. */ title?: string /** * Adresse der Quelle. Bei einer aktiven Lesequelle ist das die Seite, die * Livias Recherchelauf tatsächlich abruft — der angezeigte Link und der * gelesene Link sind damit derselbe Wert. */ url?: string /** Wofür der Agent dieses System nutzt — in Alltagssprache, ohne KI-Jargon. */ usage: string /** Klartext zur Berechtigung, z. B. «Schreibt erst nach Freigabe». */ permissionNote: string } // ── Aufgaben ────────────────────────────────────────────────────────────────── export interface AgentTask { id: string title: string description: string enabled: boolean /** Zeitplan oder auslösendes Ereignis, z. B. «täglich 06:00» oder «bei Eingang». */ schedule: string requiresApproval: boolean dependsOnChannel?: AgentChannelType dependsOnSystem?: AgentSystemType } // ── Einstellungen ───────────────────────────────────────────────────────────── export const AgentSettingKind = { TEXT: 'TEXT', NUMBER: 'NUMBER', SELECT: 'SELECT', MULTI_SELECT: 'MULTI_SELECT', BOOLEAN: 'BOOLEAN', TIME: 'TIME', /** * Mehrfachauswahl als Chips, jeder einzeln entfernbar (Runde 10, §§2.7–2.9). * * Der Unterschied zu `MULTI_SELECT` ist nicht bloss die Darstellung: Ein * Auswahlfeld kann nur anbieten, was jemand vorher als Option hinterlegt * hat. Quellentypen und Beobachtungsräume sind aber genau das, was sich von * Haus zu Haus unterscheidet — sie brauchen ein Feld, in das man schreiben * kann, was man meint. */ CHIPS: 'CHIPS', /** Abgelegte Dokumente als Datenbasis der Recherche (Runde 10, §2.6). */ DOCUMENTS: 'DOCUMENTS', } as const export type AgentSettingKind = typeof AgentSettingKind[keyof typeof AgentSettingKind] export const AgentSettingGroup = { GENERAL: 'GENERAL', APPROVAL: 'APPROVAL', DELIVERY: 'DELIVERY', SPECIFIC: 'SPECIFIC', } as const export type AgentSettingGroup = typeof AgentSettingGroup[keyof typeof AgentSettingGroup] export interface AgentSettingOption { value: string label: string } export interface AgentSetting { id: string label: string description?: string kind: AgentSettingKind group: AgentSettingGroup value: string | number | boolean | string[] options?: AgentSettingOption[] unit?: string min?: number max?: number /** Fachlich nicht abschaltbar — z. B. Sinas Quellenzwang. */ locked?: boolean lockedReason?: string /** * Erklärt auf Knopfdruck, wie ein Wert zustande kommt (Runde 10, §2.10). * * Gehört ans Datenmodell und nicht in die Komponente: Was ein Schwellenwert * bedeutet, weiss das Personalblatt, nicht das Eingabefeld. Und ein Text, * der eine Berechnung beschreibt, muss neben der Berechnung stehen, damit * beide zusammen geändert werden. */ infoText?: string /** * Nur bei `CHIPS`: ob eigene Werte erfasst werden dürfen. Bei einer * fachlich abgeschlossenen Liste — etwa den drei Zeitfenstern — bleibt es * aus, sonst entstünde ein vierter Wert, den niemand auswerten kann. */ allowCustom?: boolean } // ── Kennzahlen & Profil ─────────────────────────────────────────────────────── export interface AgentMetric { id: string label: string value: string hint?: string } /** Informationsbox unter dem Kopfbereich des Personalblatts (§7.6). */ export interface AgentProfile { purpose: string input: string[] coreFlow: string[] output: string[] } // ── Entität ─────────────────────────────────────────────────────────────────── /** * Farbton des Avatars. Bewusst ein Token-Schlüssel statt eines Hex-Werts — * `npm run check:tokens` liegt über dem Schwellwert und darf nicht wachsen. */ export const AgentAvatarTone = { BRAND: 'BRAND', SUCCESS: 'SUCCESS', INFO: 'INFO', SIGNAL: 'SIGNAL', WARNING: 'WARNING', GOLD: 'GOLD', SLATE: 'SLATE', } as const export type AgentAvatarTone = typeof AgentAvatarTone[keyof typeof AgentAvatarTone] export interface TeamAgent { id: string name: string role: string personnelNumber: string department: string email: string avatarTone: AgentAvatarTone status: AgentStatus autonomyLevel: AgentAutonomyLevel /** Ein Satz für Karte und Listeneintrag. */ shortDescription: string /** Freitext zur Autonomie, wo der Katalog differenziert («autonom beim Erinnern, Freigabe bei Eskalationen»). */ autonomyNote: string profile: AgentProfile responsibilities: string[] tasks: AgentTask[] channels: AgentChannel[] systems: AgentSystem[] settings: AgentSetting[] metrics: AgentMetric[] /** Kurzkennzahl für die Agentenkarte auf der Teamübersicht. */ headlineMetricId: string lastRun?: string } // ── Schreib-Inputs ──────────────────────────────────────────────────────────── export interface UpdateTeamAgentInput { status?: AgentStatus tasks?: AgentTask[] channels?: AgentChannel[] /** Systeme sind seit Runde 10 (§2) genauso bearbeitbar wie Aufgaben und Kanäle. */ systems?: AgentSystem[] settings?: AgentSetting[] }