mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-22 03:06:41 +02:00
feat(ai): policy is read from the owning agent (Phase 4)
Until now AiPolicy lived as a user-global setting consulted for every AI action. With agents as the principal unit of AI behavior, policy belongs on the agent — different agents can be aggressive about tasks but conservative about calendar edits, etc. Webapp (tools/executor.ts): - When an AI actor invokes a tool, the executor looks up the owning agent via getAgent(actor.principalId) and passes agent.policy into resolvePolicy. Falls back to DEFAULT_AI_POLICY when the agent record is missing (legacy write, deleted agent, race) so no tool call can silently bypass the propose/deny path. - resolvePolicy already accepted an optional policy arg, so the call site change is a single line plus the agent load. Server (mana-ai): - ServerAgent gains an optional policy field, projected off the same plaintext JSONB that the webapp writes. - Tick loop filters AI_AVAILABLE_TOOLS through filterToolsByAgentPolicy before passing them to the planner prompt. Resolution order mirrors the webapp: tools[name] → defaultsByModule → defaultForAi; 'deny' drops the tool so the LLM never even sees it. Phase 5 will surface a per-agent policy editor on the agent-detail UI. Until then all agents inherit DEFAULT_AI_POLICY (baked in during createAgent), which means no behavior change for existing users — every tool that was 'propose' before is still 'propose' now, just reached via agent.policy instead of the user-level singleton. Tests: mana-ai 41/41, webapp svelte-check clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
968e08059f
commit
f7426ab40f
3 changed files with 49 additions and 2 deletions
|
|
@ -17,7 +17,9 @@ import { getTool } from './registry';
|
|||
import { runAsAsync, USER_ACTOR } from '../events/actor';
|
||||
import { resolvePolicy } from '../ai/policy';
|
||||
import { createProposal } from '../ai/proposals/store';
|
||||
import { getAgent } from '../ai/agents/store';
|
||||
import type { Actor } from '../events/actor';
|
||||
import type { AiPolicy } from '@mana/shared-ai';
|
||||
import type { ToolResult } from './types';
|
||||
|
||||
export async function executeTool(
|
||||
|
|
@ -34,7 +36,18 @@ export async function executeTool(
|
|||
if (!validation.ok) return validation.error;
|
||||
|
||||
const effectiveActor: Actor = actor ?? USER_ACTOR;
|
||||
const decision = resolvePolicy(name, effectiveActor);
|
||||
|
||||
// Multi-Agent Workbench (Phase 4): policy lives on the agent. When
|
||||
// the actor is AI, look up the owning agent and use its policy. If
|
||||
// the agent record is missing (legacy write, deleted agent, race),
|
||||
// resolvePolicy falls back to the user-level DEFAULT_AI_POLICY via
|
||||
// its optional-argument default.
|
||||
let agentPolicy: AiPolicy | undefined;
|
||||
if (effectiveActor.kind === 'ai') {
|
||||
const agent = await getAgent(effectiveActor.principalId);
|
||||
agentPolicy = agent?.policy;
|
||||
}
|
||||
const decision = resolvePolicy(name, effectiveActor, agentPolicy);
|
||||
|
||||
if (decision === 'deny') {
|
||||
return {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue