feat(ai-tools): unlock create_note + create_journal_entry + habit tools for agents

Closes the three biggest tool-coverage gaps so the shipped agent
templates can actually do their job end-to-end. Before this, the
Recherche-Agent couldn't create notes (only edit), the Today-Agent
couldn't create journal entries, and no habit-related tool was
server-proposable at all.

shared-ai (proposable-tools.ts):
- create_note (notes) — key unlock: Recherche-Agent now creates
  per-source notes and the summary report.
- create_journal_entry (journal) — key unlock: Today-Agent proposes
  a poem as a journal entry with optional mood.
- create_habit (habits) — agent can suggest new habits.
- log_habit (habits) — agent can log a habit completion for today.

Organized the list with per-module section comments for readability
now that we're at 15 proposable tools.

mana-ai (planner/tools.ts):
- 5 new tool definitions with full parameter schemas:
  * create_note (title, content?)
  * create_journal_entry (content, title?, mood? enum)
  * create_habit (title, icon, color)
  * log_habit (habitId, note?)
- Drift-guard contract test passes (41/41) — confirms the mana-ai
  tool list is in sync with the shared-ai canonical set.

Webapp (policy.ts):
- get_habits added to AUTO_TOOLS (read-only; agent can inspect
  which habits exist without nagging the user for approval).
- list_notes added to AUTO_TOOLS (was already used in the reasoning
  loop but missing from the explicit auto-list; the planner default
  fell through to 'propose' which was wasteful for a read op).

Module coverage after this change:
   todo (5 tools)   calendar (2)   notes (5 incl. create)
   places (4)       drink (3)      food (2)
   news (1)         journal (1)    habits (3)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-16 12:00:17 +02:00
parent bc5c15096c
commit 1266b583e4
3 changed files with 76 additions and 0 deletions

View file

@ -41,11 +41,13 @@ export interface AiPolicy {
const AUTO_TOOLS: Record<string, 'auto'> = {
get_task_stats: 'auto',
list_tasks: 'auto',
list_notes: 'auto',
get_todays_events: 'auto',
get_drink_progress: 'auto',
nutrition_summary: 'auto',
get_places: 'auto',
location_log: 'auto',
get_habits: 'auto',
// Append-only self-state logs: AI proposing "did you drink water?" +
// user confirming + AI logging it should not require a second approval.
log_drink: 'auto',

View file

@ -17,17 +17,29 @@
*/
export const AI_PROPOSABLE_TOOL_NAMES = [
// ── Todo ──────────────────────────────────
'create_task',
'complete_task',
'complete_tasks_by_title',
// ── Calendar ──────────────────────────────
'create_event',
// ── Places ────────────────────────────────
'create_place',
'visit_place',
// ── Drink ─────────────────────────────────
'undo_drink',
// ── News ──────────────────────────────────
'save_news_article',
// ── Notes ─────────────────────────────────
'create_note',
'update_note',
'append_to_note',
'add_tag_to_note',
// ── Journal ───────────────────────────────
'create_journal_entry',
// ── Habits ────────────────────────────────
'create_habit',
'log_habit',
] as const;
export type AiProposableToolName = (typeof AI_PROPOSABLE_TOOL_NAMES)[number];

View file

@ -146,6 +146,68 @@ export const AI_AVAILABLE_TOOLS: readonly AvailableTool[] = [
},
],
},
// ── Notes: create ────────────────────────────────────────
{
name: 'create_note',
module: 'notes',
description: 'Erstellt eine neue Notiz. Gibt die ID der angelegten Notiz zurueck.',
parameters: [
{ name: 'title', type: 'string', description: 'Titel der Notiz', required: true },
{
name: 'content',
type: 'string',
description: 'Inhalt der Notiz (Markdown)',
required: false,
},
],
},
// ── Journal ──────────────────────────────────────────────
{
name: 'create_journal_entry',
module: 'journal',
description:
'Erstellt einen neuen Tagebuch-Eintrag fuer den heutigen Tag. Gibt die ID zurueck.',
parameters: [
{
name: 'content',
type: 'string',
description: 'Inhalt des Eintrags (Markdown)',
required: true,
},
{ name: 'title', type: 'string', description: 'Optionaler Titel', required: false },
{
name: 'mood',
type: 'string',
description: 'Stimmung',
required: false,
enum: ['great', 'good', 'neutral', 'bad', 'terrible'],
},
],
},
// ── Habits ───────────────────────────────────────────────
{
name: 'create_habit',
module: 'habits',
description: 'Erstellt einen neuen Habit-Tracker. Gibt die ID des neuen Habits zurueck.',
parameters: [
{ name: 'title', type: 'string', description: 'Titel des Habits', required: true },
{ name: 'icon', type: 'string', description: 'Emoji-Icon', required: true },
{ name: 'color', type: 'string', description: 'Hex-Farbe (z.B. #EF4444)', required: true },
],
},
{
name: 'log_habit',
module: 'habits',
description:
'Loggt eine Ausfuehrung eines existierenden Habits fuer heute. Optional mit Notiz.',
parameters: [
{ name: 'habitId', type: 'string', description: 'ID des Habits', required: true },
{ name: 'note', type: 'string', description: 'Optionale Notiz zum Log', required: false },
],
},
];
export const AI_AVAILABLE_TOOL_NAMES = new Set<string>(AI_AVAILABLE_TOOLS.map((t) => t.name));