feat(ai): tag-based agent scoping — agents see only their tagged records

Connects the existing global tag system (@mana/shared-tags, 15+ module
junctions, TagSelector UI) to the AI agent model so different agents
can operate on different slices of the user's data.

Core additions:

1. Agent.scopeTagIds — optional array of global tag IDs. When set,
   the agent sees only records tagged with at least one of those tags
   (plus untagged records, which stay globally visible). Empty/undefined
   = General-Agent, sees everything. Agent-editor grows a <TagSelector>
   under "Bereiche (Tag-Scope)".

2. Per-agent kontext documents — new Dexie table `agentKontextDocs`
   (v22, encrypted, synced). Each agent can have its own markdown
   context doc, replacing the global singleton auto-inject. Runner
   tries agent kontext first, falls back to global singleton when
   the agent has no dedicated doc.

3. Ambient scope context — `withAgentScope(tagIds, fn)` sets a
   module-level scope during the reasoning loop. Auto-tools read it
   via `getAgentScopeTagIds()` and filter their result sets.
   `filterByScope(records, getTagIds)` is the reusable filter
   primitive (keeps untagged records, drops mismatched tagged ones).

4. Notes tag junction — `noteTags` table (v22) + `noteTagOps` via
   `createTagLinkOps`. Notes was the only major module without
   structured tag support. `list_notes` now calls `filterByScope`
   so a scoped agent only sees notes tagged with its scope.

Flow: mission starts → runner resolves owning agent → reads
agent.scopeTagIds → wraps entire reasoning loop in withAgentScope →
list_notes (and future list_tasks etc.) auto-filter → planner sees
only scope-relevant records → proposes scoped edits.

Runner tests: 8/8. shared-ai type-check: clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-16 13:43:33 +02:00
parent 3f60f68573
commit 10acabfed6
11 changed files with 232 additions and 7 deletions

View file

@ -47,6 +47,13 @@ export interface Agent {
* rest. */
memory?: string;
/** Tag-based data scope the agent sees only records tagged with at
* least one of these global tags (+ untagged records). Empty array or
* undefined = agent sees everything (General-Agent). IDs reference
* the shared `tags` table managed by `@mana/shared-tags`. Plaintext
* (tag IDs are not sensitive). */
scopeTagIds?: string[];
/** Per-tool allowlist/propose/deny. Replaces the user-level AiPolicy
* in Phase 4; pre-populated with the default policy at create time
* so the runner can start reading it even while still consulting