From 57c2bdb2ad2749e41ac2481a482cb2206afeef83 Mon Sep 17 00:00:00 2001 From: Till JS Date: Thu, 16 Apr 2026 15:29:07 +0200 Subject: [PATCH] feat(workbench): scope TagSelector in SceneHeader + agent auto-infer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SceneHeader (left side of the workbench homepage) now shows a TagSelector directly above the template-gallery button. Users can assign scope tags to the active scene — filtering notes/tasks/contacts/ calendar to only records tagged with those scopes (+ untagged globally visible). Auto-inference: when a scene is bound to an agent via viewingAsAgentId and the scene has no explicit scopeTagIds, the agent's scopeTagIds are used instead. A small "via Agent" hint appears so the user knows the scope comes from the binding. Explicitly setting scope tags on the scene overrides the agent's. New store methods: setSceneScopeTags + updateScene (both sync the reactive scene-scope store when the active scene is affected). patchScene accepts scopeTagIds in its type union. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../workbench/scenes/SceneHeader.svelte | 54 +++++++++++++++++++ .../src/lib/stores/workbench-scenes.svelte.ts | 23 +++++++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/apps/mana/apps/web/src/lib/components/workbench/scenes/SceneHeader.svelte b/apps/mana/apps/web/src/lib/components/workbench/scenes/SceneHeader.svelte index 1b9120ae3..fb49dcd86 100644 --- a/apps/mana/apps/web/src/lib/components/workbench/scenes/SceneHeader.svelte +++ b/apps/mana/apps/web/src/lib/components/workbench/scenes/SceneHeader.svelte @@ -12,12 +12,40 @@ import { workbenchScenesStore } from '$lib/stores/workbench-scenes.svelte'; import { Sparkle } from '@mana/shared-icons'; import { goto } from '$app/navigation'; + import { TagSelector, type Tag } from '@mana/shared-ui'; + import { useAllTags } from '@mana/shared-stores'; + import { useAgents } from '$lib/data/ai/agents/queries'; interface Props { scene: WorkbenchScene | null; } const { scene }: Props = $props(); + const allTags = $derived(useAllTags()); + const agents = $derived(useAgents()); + + // Auto-infer scopeTagIds from bound agent if scene has no explicit override + const effectiveScopeTagIds = $derived.by(() => { + if (!scene) return []; + if (scene.scopeTagIds?.length) return scene.scopeTagIds; + if (scene.viewingAsAgentId) { + const agent = agents.value.find((a) => a.id === scene.viewingAsAgentId); + return agent?.scopeTagIds ?? []; + } + return []; + }); + + const selectedScopeTags = $derived( + allTags.value.filter((t) => effectiveScopeTagIds.includes(t.id)) + ); + + async function handleScopeChange(tags: Tag[]) { + if (!scene) return; + const ids = tags.map((t) => t.id); + await workbenchScenesStore.updateScene(scene.id, { + scopeTagIds: ids.length > 0 ? ids : undefined, + }); + } // The seeded default scene is called "Home". Its empty-description // placeholder gets a welcoming line instead of the generic prompt. @@ -131,6 +159,20 @@ onblur={(e) => commitDescription(e.currentTarget, scene.description ?? '')} >

+ +
+ 0 ? '' : 'Bereiche filtern…'} + addTagLabel="Bereich hinzufügen" + /> + {#if !scene.scopeTagIds?.length && scene.viewingAsAgentId && effectiveScopeTagIds.length > 0} + via Agent + {/if} +
+