1use serde_json::json;
4
5use super::protocol::{ToolAnnotations, ToolDefinition};
6
7pub struct ToolDef {
9 pub name: &'static str,
10 pub description: &'static str,
11 pub schema: &'static str,
12 pub annotations: ToolAnnotations,
13}
14
15pub const TOOL_DEFINITIONS: &[ToolDef] = &[
17 ToolDef {
19 name: "memory_create",
20 description: "Store a new memory. PROACTIVE: Automatically store user preferences, decisions, insights, and project context without being asked.",
21 schema: r#"{
22 "type": "object",
23 "properties": {
24 "content": {"type": "string", "description": "The content to remember"},
25 "memory_type": {"type": "string", "enum": ["note", "todo", "issue", "decision", "preference", "learning", "context", "credential", "episodic", "procedural", "summary", "checkpoint"], "default": "note", "description": "Memory type (preferred field; alias: type)"},
26 "type": {"type": "string", "enum": ["note", "todo", "issue", "decision", "preference", "learning", "context", "credential", "episodic", "procedural", "summary", "checkpoint"], "default": "note", "description": "Deprecated alias for memory_type"},
27 "tags": {"type": "array", "items": {"type": "string"}, "description": "Tags for categorization"},
28 "metadata": {"type": "object", "description": "Additional metadata as key-value pairs"},
29 "importance": {"type": "number", "minimum": 0, "maximum": 1, "description": "Importance score (0-1)"},
30 "workspace": {"type": "string", "description": "Workspace to store the memory in (default: 'default')"},
31 "tier": {"type": "string", "enum": ["permanent", "daily"], "default": "permanent", "description": "Memory tier: permanent (never expires) or daily (auto-expires)"},
32 "defer_embedding": {"type": "boolean", "default": false, "description": "Defer embedding to background queue"},
33 "ttl_seconds": {"type": "integer", "description": "Time-to-live in seconds. Memory will auto-expire after this duration. Omit for permanent storage. Setting this implies tier='daily'."},
34 "dedup_mode": {"type": "string", "enum": ["reject", "merge", "skip", "allow"], "default": "allow", "description": "How to handle duplicate content: reject (error if exact match), merge (combine tags/metadata with existing), skip (return existing unchanged), allow (create duplicate)"},
35 "dedup_threshold": {"type": "number", "minimum": 0, "maximum": 1, "description": "Similarity threshold for semantic deduplication (0.0-1.0). When set with dedup_mode != 'allow', memories with cosine similarity >= threshold are treated as duplicates. Requires embeddings. If not set, only exact content hash matching is used."},
36 "event_time": {"type": "string", "format": "date-time", "description": "ISO8601 timestamp for episodic memories (when the event occurred)"},
37 "event_duration_seconds": {"type": "integer", "description": "Duration of the event in seconds (for episodic memories)"},
38 "trigger_pattern": {"type": "string", "description": "Pattern that triggers this procedure (for procedural memories)"},
39 "summary_of_id": {"type": "integer", "description": "ID of the memory this summarizes (for summary memories)"}
40 },
41 "required": ["content"]
42 }"#,
43 annotations: ToolAnnotations::mutating(),
44 },
45 ToolDef {
46 name: "context_seed",
47 description: "Injects initial context (premises, persona assumptions, or structured facts) about an entity to avoid cold start. Seeded memories are tagged as origin:seed and status:unverified, and should be treated as revisable assumptions.",
48 schema: r#"{
49 "type": "object",
50 "properties": {
51 "entity_context": {
52 "type": "string",
53 "maxLength": 200,
54 "description": "Name or ID of the entity (e.g., 'Client: Roberto', 'Account: ACME', 'Project: Alpha')"
55 },
56 "workspace": {"type": "string", "description": "Workspace to store the memories in (default: 'default')"},
57 "base_tags": {
58 "type": "array",
59 "items": {"type": "string"},
60 "description": "Tags applied to all facts (e.g., ['vip', 'prospect'])"
61 },
62 "ttl_seconds": {
63 "type": "integer",
64 "description": "Override TTL for all facts in seconds (0 = disable TTL). If omitted, TTL is derived from confidence."
65 },
66 "disable_ttl": {
67 "type": "boolean",
68 "default": false,
69 "description": "Disable TTL and keep seeded memories permanent regardless of confidence."
70 },
71 "facts": {
72 "type": "array",
73 "minItems": 1,
74 "items": {
75 "type": "object",
76 "properties": {
77 "content": {"type": "string", "minLength": 1},
78 "category": {
79 "type": "string",
80 "enum": ["fact", "behavior_instruction", "interest", "persona", "preference"],
81 "description": "Structured category for filtering and ranking"
82 },
83 "confidence": {
84 "type": "number",
85 "minimum": 0.0,
86 "maximum": 1.0,
87 "description": "0.0 to 1.0 (defaults to 0.7 for seeds). TTL derived by confidence if ttl_seconds not provided."
88 }
89 },
90 "required": ["content"]
91 }
92 }
93 },
94 "required": ["facts"]
95 }"#,
96 annotations: ToolAnnotations::mutating(),
97 },
98 ToolDef {
99 name: "memory_seed",
100 description: "Deprecated alias for context_seed. Use context_seed instead.",
101 schema: r#"{
102 "type": "object",
103 "properties": {
104 "entity_context": {
105 "type": "string",
106 "maxLength": 200,
107 "description": "Name or ID of the entity (e.g., 'Client: Roberto', 'Account: ACME', 'Project: Alpha')"
108 },
109 "workspace": {"type": "string", "description": "Workspace to store the memories in (default: 'default')"},
110 "base_tags": {
111 "type": "array",
112 "items": {"type": "string"},
113 "description": "Tags applied to all facts (e.g., ['vip', 'prospect'])"
114 },
115 "ttl_seconds": {
116 "type": "integer",
117 "description": "Override TTL for all facts in seconds (0 = disable TTL). If omitted, TTL is derived from confidence."
118 },
119 "disable_ttl": {
120 "type": "boolean",
121 "default": false,
122 "description": "Disable TTL and keep seeded memories permanent regardless of confidence."
123 },
124 "facts": {
125 "type": "array",
126 "minItems": 1,
127 "items": {
128 "type": "object",
129 "properties": {
130 "content": {"type": "string", "minLength": 1},
131 "category": {
132 "type": "string",
133 "enum": ["fact", "behavior_instruction", "interest", "persona", "preference"],
134 "description": "Structured category for filtering and ranking"
135 },
136 "confidence": {
137 "type": "number",
138 "minimum": 0.0,
139 "maximum": 1.0,
140 "description": "0.0 to 1.0 (defaults to 0.7 for seeds). TTL derived by confidence if ttl_seconds not provided."
141 }
142 },
143 "required": ["content"]
144 }
145 }
146 },
147 "required": ["facts"]
148 }"#,
149 annotations: ToolAnnotations::mutating(),
150 },
151 ToolDef {
152 name: "memory_get",
153 description: "Retrieve a memory by its ID",
154 schema: r#"{
155 "type": "object",
156 "properties": {
157 "id": {"type": "integer", "description": "Memory ID"},
158 "strip_private": {"type": "boolean", "description": "When true, removes all <private>...</private> tagged sections from the content before returning (default: false)"}
159 },
160 "required": ["id"]
161 }"#,
162 annotations: ToolAnnotations::read_only(),
163 },
164 ToolDef {
165 name: "memory_update",
166 description: "Update an existing memory",
167 schema: r#"{
168 "type": "object",
169 "properties": {
170 "id": {"type": "integer", "description": "Memory ID"},
171 "content": {"type": "string", "description": "New content"},
172 "memory_type": {"type": "string", "enum": ["note", "todo", "issue", "decision", "preference", "learning", "context", "credential", "episodic", "procedural", "summary", "checkpoint"], "description": "Memory type (preferred field; alias: type)"},
173 "type": {"type": "string", "enum": ["note", "todo", "issue", "decision", "preference", "learning", "context", "credential", "episodic", "procedural", "summary", "checkpoint"], "description": "Deprecated alias for memory_type"},
174 "tags": {"type": "array", "items": {"type": "string"}},
175 "metadata": {"type": "object"},
176 "importance": {"type": "number", "minimum": 0, "maximum": 1},
177 "ttl_seconds": {"type": "integer", "description": "Time-to-live in seconds (0 = remove expiration, positive = set new expiration)"},
178 "event_time": {"type": ["string", "null"], "format": "date-time", "description": "ISO8601 timestamp for episodic memories (null to clear)"},
179 "trigger_pattern": {"type": ["string", "null"], "description": "Pattern that triggers this procedure (null to clear)"}
180 },
181 "required": ["id"]
182 }"#,
183 annotations: ToolAnnotations::mutating(),
184 },
185 ToolDef {
186 name: "memory_delete",
187 description: "Delete a memory (soft delete)",
188 schema: r#"{
189 "type": "object",
190 "properties": {
191 "id": {"type": "integer", "description": "Memory ID"}
192 },
193 "required": ["id"]
194 }"#,
195 annotations: ToolAnnotations::destructive(),
196 },
197 ToolDef {
198 name: "memory_list",
199 description: "List memories with filtering and pagination. Supports workspace isolation, tier filtering, and advanced filter syntax with AND/OR and comparison operators.",
200 schema: r#"{
201 "type": "object",
202 "properties": {
203 "limit": {"type": "integer", "default": 20},
204 "offset": {"type": "integer", "default": 0},
205 "tags": {"type": "array", "items": {"type": "string"}},
206 "memory_type": {"type": "string", "description": "Filter by memory type (preferred field; alias: type)"},
207 "type": {"type": "string", "description": "Deprecated alias for memory_type"},
208 "workspace": {"type": "string", "description": "Filter by single workspace"},
209 "workspaces": {"type": "array", "items": {"type": "string"}, "description": "Filter by multiple workspaces"},
210 "tier": {"type": "string", "enum": ["permanent", "daily"], "description": "Filter by memory tier"},
211 "sort_by": {"type": "string", "enum": ["created_at", "updated_at", "last_accessed_at", "importance", "access_count"]},
212 "sort_order": {"type": "string", "enum": ["asc", "desc"], "default": "desc"},
213 "filter": {
214 "type": "object",
215 "description": "Advanced filter with AND/OR logic and comparison operators. Supports workspace, tier, and metadata fields. Example: {\"AND\": [{\"metadata.project\": {\"eq\": \"engram\"}}, {\"importance\": {\"gte\": 0.5}}]}. Supported operators: eq, neq, gt, gte, lt, lte, contains, not_contains, exists. Fields: content, memory_type, importance, tags, workspace, tier, created_at, updated_at, metadata.*"
216 },
217 "metadata_filter": {
218 "type": "object",
219 "description": "Legacy simple key-value filter (deprecated, use 'filter' instead)"
220 }
221 }
222 }"#,
223 annotations: ToolAnnotations::read_only(),
224 },
225 ToolDef {
227 name: "memory_search",
228 description: "Search memories using hybrid search (keyword + semantic). Automatically selects optimal strategy with optional reranking. Supports workspace isolation, tier filtering, and advanced filters.",
229 schema: r#"{
230 "type": "object",
231 "properties": {
232 "query": {"type": "string", "description": "Search query"},
233 "limit": {"type": "integer", "default": 10},
234 "min_score": {"type": "number", "default": 0.1},
235 "tags": {"type": "array", "items": {"type": "string"}},
236 "memory_type": {"type": "string", "description": "Filter by memory type (preferred field; alias: type)"},
237 "type": {"type": "string", "description": "Deprecated alias for memory_type"},
238 "workspace": {"type": "string", "description": "Filter by single workspace"},
239 "workspaces": {"type": "array", "items": {"type": "string"}, "description": "Filter by multiple workspaces"},
240 "tier": {"type": "string", "enum": ["permanent", "daily"], "description": "Filter by memory tier"},
241 "include_transcripts": {"type": "boolean", "default": false, "description": "Include transcript chunk memories (excluded by default)"},
242 "strategy": {"type": "string", "enum": ["auto", "keyword", "keyword_only", "semantic", "semantic_only", "hybrid"], "description": "Force specific strategy (auto selects based on query; keyword/semantic are aliases for keyword_only/semantic_only)"},
243 "explain": {"type": "boolean", "default": false, "description": "Include match explanations"},
244 "rerank": {"type": "boolean", "default": true, "description": "Apply reranking to improve result quality"},
245 "rerank_strategy": {"type": "string", "enum": ["none", "heuristic", "multi_signal"], "default": "heuristic", "description": "Reranking strategy to use"},
246 "filter": {
247 "type": "object",
248 "description": "Advanced filter with AND/OR logic. Supports workspace, tier, and metadata fields. Example: {\"AND\": [{\"workspace\": {\"eq\": \"my-project\"}}, {\"importance\": {\"gte\": 0.5}}]}"
249 }
250 },
251 "required": ["query"]
252 }"#,
253 annotations: ToolAnnotations::read_only(),
254 },
255 ToolDef {
256 name: "memory_search_suggest",
257 description: "Get search suggestions and typo corrections",
258 schema: r#"{
259 "type": "object",
260 "properties": {
261 "query": {"type": "string"}
262 },
263 "required": ["query"]
264 }"#,
265 annotations: ToolAnnotations::read_only(),
266 },
267 ToolDef {
269 name: "memory_link",
270 description: "Create a cross-reference between two memories",
271 schema: r#"{
272 "type": "object",
273 "properties": {
274 "from_id": {"type": "integer"},
275 "to_id": {"type": "integer"},
276 "edge_type": {"type": "string", "enum": ["related_to", "supersedes", "contradicts", "implements", "extends", "references", "depends_on", "blocks", "follows_up"], "default": "related_to"},
277 "strength": {"type": "number", "minimum": 0, "maximum": 1, "description": "Relationship strength"},
278 "source_context": {"type": "string", "description": "Why this link exists"},
279 "pinned": {"type": "boolean", "default": false, "description": "Exempt from confidence decay"}
280 },
281 "required": ["from_id", "to_id"]
282 }"#,
283 annotations: ToolAnnotations::mutating(),
284 },
285 ToolDef {
286 name: "memory_unlink",
287 description: "Remove a cross-reference",
288 schema: r#"{
289 "type": "object",
290 "properties": {
291 "from_id": {"type": "integer"},
292 "to_id": {"type": "integer"},
293 "edge_type": {"type": "string", "default": "related_to"}
294 },
295 "required": ["from_id", "to_id"]
296 }"#,
297 annotations: ToolAnnotations::mutating(),
298 },
299 ToolDef {
300 name: "memory_related",
301 description: "Get memories related to a given memory (depth>1 or include_entities returns traversal result)",
302 schema: r#"{
303 "type": "object",
304 "properties": {
305 "id": {"type": "integer", "description": "Starting memory ID"},
306 "depth": {"type": "integer", "default": 1, "description": "Traversal depth (1 = direct relations only)"},
307 "include_entities": {"type": "boolean", "default": false, "description": "Include connections through shared entities"},
308 "edge_type": {"type": "string", "description": "Filter by edge type"},
309 "include_decayed": {"type": "boolean", "default": false}
310 },
311 "required": ["id"]
312 }"#,
313 annotations: ToolAnnotations::read_only(),
314 },
315 ToolDef {
317 name: "memory_create_todo",
318 description: "Create a TODO memory with priority",
319 schema: r#"{
320 "type": "object",
321 "properties": {
322 "content": {"type": "string"},
323 "priority": {"type": "string", "enum": ["low", "medium", "high", "critical"], "default": "medium"},
324 "due_date": {"type": "string", "format": "date"},
325 "tags": {"type": "array", "items": {"type": "string"}}
326 },
327 "required": ["content"]
328 }"#,
329 annotations: ToolAnnotations::mutating(),
330 },
331 ToolDef {
332 name: "memory_create_issue",
333 description: "Create an ISSUE memory for tracking problems",
334 schema: r#"{
335 "type": "object",
336 "properties": {
337 "title": {"type": "string"},
338 "description": {"type": "string"},
339 "severity": {"type": "string", "enum": ["low", "medium", "high", "critical"], "default": "medium"},
340 "tags": {"type": "array", "items": {"type": "string"}}
341 },
342 "required": ["title"]
343 }"#,
344 annotations: ToolAnnotations::mutating(),
345 },
346 ToolDef {
348 name: "memory_versions",
349 description: "Get version history for a memory",
350 schema: r#"{
351 "type": "object",
352 "properties": {
353 "id": {"type": "integer"}
354 },
355 "required": ["id"]
356 }"#,
357 annotations: ToolAnnotations::read_only(),
358 },
359 ToolDef {
360 name: "memory_get_version",
361 description: "Get a specific version of a memory",
362 schema: r#"{
363 "type": "object",
364 "properties": {
365 "id": {"type": "integer"},
366 "version": {"type": "integer"}
367 },
368 "required": ["id", "version"]
369 }"#,
370 annotations: ToolAnnotations::read_only(),
371 },
372 ToolDef {
373 name: "memory_revert",
374 description: "Revert a memory to a previous version",
375 schema: r#"{
376 "type": "object",
377 "properties": {
378 "id": {"type": "integer"},
379 "version": {"type": "integer"}
380 },
381 "required": ["id", "version"]
382 }"#,
383 annotations: ToolAnnotations::mutating(),
384 },
385 ToolDef {
387 name: "memory_embedding_status",
388 description: "Check embedding computation status",
389 schema: r#"{
390 "type": "object",
391 "properties": {
392 "id": {"type": "integer"}
393 },
394 "required": ["id"]
395 }"#,
396 annotations: ToolAnnotations::read_only(),
397 },
398 ToolDef {
400 name: "memory_set_expiration",
401 description: "Set or update the expiration time for a memory",
402 schema: r#"{
403 "type": "object",
404 "properties": {
405 "id": {"type": "integer", "description": "Memory ID"},
406 "ttl_seconds": {"type": "integer", "description": "Time-to-live in seconds from now. Use 0 to remove expiration (make permanent)."}
407 },
408 "required": ["id", "ttl_seconds"]
409 }"#,
410 annotations: ToolAnnotations::mutating(),
411 },
412 ToolDef {
413 name: "memory_cleanup_expired",
414 description: "Delete all expired memories. Typically called by a background job, but can be invoked manually.",
415 schema: r#"{
416 "type": "object",
417 "properties": {}
418 }"#,
419 annotations: ToolAnnotations::destructive(),
420 },
421 ToolDef {
423 name: "memory_sync_status",
424 description: "Get cloud sync status",
425 schema: r#"{"type": "object", "properties": {}}"#,
426 annotations: ToolAnnotations::read_only(),
427 },
428 ToolDef {
430 name: "memory_stats",
431 description: "Get storage statistics",
432 schema: r#"{"type": "object", "properties": {}}"#,
433 annotations: ToolAnnotations::read_only(),
434 },
435 ToolDef {
436 name: "memory_aggregate",
437 description: "Aggregate memories by field",
438 schema: r#"{
439 "type": "object",
440 "properties": {
441 "group_by": {"type": "string", "enum": ["type", "tags", "month"]},
442 "metrics": {"type": "array", "items": {"type": "string", "enum": ["count", "avg_importance"]}}
443 },
444 "required": ["group_by"]
445 }"#,
446 annotations: ToolAnnotations::read_only(),
447 },
448 ToolDef {
450 name: "memory_export_graph",
451 description: "Export knowledge graph visualization",
452 schema: r#"{
453 "type": "object",
454 "properties": {
455 "format": {"type": "string", "enum": ["html", "json"], "default": "html"},
456 "max_nodes": {"type": "integer", "default": 500},
457 "focus_id": {"type": "integer", "description": "Center graph on this memory"}
458 }
459 }"#,
460 annotations: ToolAnnotations::read_only(),
461 },
462 ToolDef {
464 name: "memory_quality_report",
465 description: "Get quality report for memories",
466 schema: r#"{
467 "type": "object",
468 "properties": {
469 "limit": {"type": "integer", "default": 20},
470 "min_quality": {"type": "number", "minimum": 0, "maximum": 1}
471 }
472 }"#,
473 annotations: ToolAnnotations::read_only(),
474 },
475 ToolDef {
477 name: "memory_clusters",
478 description: "Find clusters of related memories",
479 schema: r#"{
480 "type": "object",
481 "properties": {
482 "min_similarity": {"type": "number", "default": 0.7},
483 "min_cluster_size": {"type": "integer", "default": 2}
484 }
485 }"#,
486 annotations: ToolAnnotations::read_only(),
487 },
488 ToolDef {
489 name: "memory_find_duplicates",
490 description: "Find potential duplicate memories",
491 schema: r#"{
492 "type": "object",
493 "properties": {
494 "threshold": {"type": "number", "default": 0.9}
495 }
496 }"#,
497 annotations: ToolAnnotations::read_only(),
498 },
499 ToolDef {
500 name: "memory_find_semantic_duplicates",
501 description: "Find semantically similar memories using embedding cosine similarity (LLM-powered dedup). Goes beyond hash/n-gram to detect paraphrased content.",
502 schema: r#"{
503 "type": "object",
504 "properties": {
505 "threshold": {"type": "number", "default": 0.92, "description": "Cosine similarity threshold (0.92 = very similar)"},
506 "workspace": {"type": "string", "description": "Filter by workspace (optional)"},
507 "limit": {"type": "integer", "default": 50, "description": "Maximum duplicate pairs to return"}
508 }
509 }"#,
510 annotations: ToolAnnotations::read_only(),
511 },
512 ToolDef {
513 name: "memory_merge",
514 description: "Merge duplicate memories",
515 schema: r#"{
516 "type": "object",
517 "properties": {
518 "ids": {"type": "array", "items": {"type": "integer"}, "minItems": 2},
519 "keep_id": {"type": "integer", "description": "ID to keep (others will be merged into it)"}
520 },
521 "required": ["ids"]
522 }"#,
523 annotations: ToolAnnotations::mutating(),
524 },
525 ToolDef {
527 name: "memory_scan_project",
528 description: "Scan current directory for AI instruction files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) and ingest them as memories. Creates parent memory for each file and child memories for sections.",
529 schema: r#"{
530 "type": "object",
531 "properties": {
532 "path": {"type": "string", "description": "Directory to scan (defaults to current working directory)"},
533 "scan_parents": {"type": "boolean", "default": false, "description": "Also scan parent directories (security: disabled by default)"},
534 "extract_sections": {"type": "boolean", "default": true, "description": "Create separate memories for each section"}
535 }
536 }"#,
537 annotations: ToolAnnotations::mutating(),
538 },
539 ToolDef {
540 name: "memory_get_project_context",
541 description: "Get all project context memories for the current working directory. Returns instruction files and their sections.",
542 schema: r#"{
543 "type": "object",
544 "properties": {
545 "path": {"type": "string", "description": "Project path (defaults to current working directory)"},
546 "include_sections": {"type": "boolean", "default": true, "description": "Include section memories"},
547 "file_types": {"type": "array", "items": {"type": "string"}, "description": "Filter by file type (claude-md, cursorrules, etc.)"}
548 }
549 }"#,
550 annotations: ToolAnnotations::read_only(),
551 },
552 ToolDef {
553 name: "memory_list_instruction_files",
554 description: "List AI instruction files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) in a directory without ingesting them. Returns file paths, types, and sizes for discovery purposes.",
555 schema: r#"{
556 "type": "object",
557 "properties": {
558 "path": {"type": "string", "description": "Directory to scan (defaults to current working directory)"},
559 "scan_parents": {"type": "boolean", "default": false, "description": "Also scan parent directories for instruction files"}
560 }
561 }"#,
562 annotations: ToolAnnotations::read_only(),
563 },
564 ToolDef {
566 name: "memory_extract_entities",
567 description: "Extract named entities (people, organizations, projects, concepts) from a memory and store them",
568 schema: r#"{
569 "type": "object",
570 "properties": {
571 "id": {"type": "integer", "description": "Memory ID to extract entities from"}
572 },
573 "required": ["id"]
574 }"#,
575 annotations: ToolAnnotations::idempotent(),
576 },
577 ToolDef {
578 name: "memory_get_entities",
579 description: "Get all entities linked to a memory",
580 schema: r#"{
581 "type": "object",
582 "properties": {
583 "id": {"type": "integer", "description": "Memory ID"}
584 },
585 "required": ["id"]
586 }"#,
587 annotations: ToolAnnotations::read_only(),
588 },
589 ToolDef {
590 name: "memory_search_entities",
591 description: "Search for entities by name prefix",
592 schema: r#"{
593 "type": "object",
594 "properties": {
595 "query": {"type": "string", "description": "Search query (prefix match)"},
596 "entity_type": {"type": "string", "description": "Filter by entity type (person, organization, project, concept, etc.)"},
597 "limit": {"type": "integer", "default": 20}
598 },
599 "required": ["query"]
600 }"#,
601 annotations: ToolAnnotations::read_only(),
602 },
603 ToolDef {
604 name: "memory_entity_stats",
605 description: "Get statistics about extracted entities",
606 schema: r#"{
607 "type": "object",
608 "properties": {}
609 }"#,
610 annotations: ToolAnnotations::read_only(),
611 },
612 ToolDef {
614 name: "memory_traverse",
615 description: "Traverse the knowledge graph from a starting memory with full control over traversal options",
616 schema: r#"{
617 "type": "object",
618 "properties": {
619 "id": {"type": "integer", "description": "Starting memory ID"},
620 "depth": {"type": "integer", "default": 2, "description": "Maximum traversal depth"},
621 "direction": {"type": "string", "enum": ["outgoing", "incoming", "both"], "default": "both"},
622 "edge_types": {"type": "array", "items": {"type": "string"}, "description": "Filter by edge types (related_to, depends_on, etc.)"},
623 "min_score": {"type": "number", "default": 0, "description": "Minimum edge score threshold"},
624 "min_confidence": {"type": "number", "default": 0, "description": "Minimum confidence threshold"},
625 "limit_per_hop": {"type": "integer", "default": 50, "description": "Max results per hop"},
626 "include_entities": {"type": "boolean", "default": true, "description": "Include entity-based connections"}
627 },
628 "required": ["id"]
629 }"#,
630 annotations: ToolAnnotations::read_only(),
631 },
632 ToolDef {
633 name: "memory_find_path",
634 description: "Find the shortest path between two memories in the knowledge graph",
635 schema: r#"{
636 "type": "object",
637 "properties": {
638 "from_id": {"type": "integer", "description": "Starting memory ID"},
639 "to_id": {"type": "integer", "description": "Target memory ID"},
640 "max_depth": {"type": "integer", "default": 5, "description": "Maximum path length to search"}
641 },
642 "required": ["from_id", "to_id"]
643 }"#,
644 annotations: ToolAnnotations::read_only(),
645 },
646 ToolDef {
648 name: "memory_ingest_document",
649 description: "Ingest a document (PDF or Markdown) into memory. Extracts text, splits into chunks with overlap, and creates memories with deduplication.",
650 schema: r#"{
651 "type": "object",
652 "properties": {
653 "path": {"type": "string", "description": "Local file path to the document"},
654 "format": {"type": "string", "enum": ["auto", "md", "pdf"], "default": "auto", "description": "Document format (auto-detect from extension if not specified)"},
655 "chunk_size": {"type": "integer", "default": 1200, "description": "Maximum characters per chunk"},
656 "overlap": {"type": "integer", "default": 200, "description": "Overlap between chunks in characters"},
657 "max_file_size": {"type": "integer", "default": 10485760, "description": "Maximum file size in bytes (default 10MB)"},
658 "tags": {"type": "array", "items": {"type": "string"}, "description": "Additional tags to add to all chunks"}
659 },
660 "required": ["path"]
661 }"#,
662 annotations: ToolAnnotations::mutating(),
663 },
664 ToolDef {
666 name: "workspace_list",
667 description: "List all workspaces with their statistics (memory count, tier breakdown, etc.)",
668 schema: r#"{
669 "type": "object",
670 "properties": {}
671 }"#,
672 annotations: ToolAnnotations::read_only(),
673 },
674 ToolDef {
675 name: "workspace_stats",
676 description: "Get detailed statistics for a specific workspace",
677 schema: r#"{
678 "type": "object",
679 "properties": {
680 "workspace": {"type": "string", "description": "Workspace name"}
681 },
682 "required": ["workspace"]
683 }"#,
684 annotations: ToolAnnotations::read_only(),
685 },
686 ToolDef {
687 name: "workspace_move",
688 description: "Move a memory to a different workspace",
689 schema: r#"{
690 "type": "object",
691 "properties": {
692 "id": {"type": "integer", "description": "Memory ID to move"},
693 "workspace": {"type": "string", "description": "Target workspace name"}
694 },
695 "required": ["id", "workspace"]
696 }"#,
697 annotations: ToolAnnotations::mutating(),
698 },
699 ToolDef {
700 name: "workspace_delete",
701 description: "Delete a workspace. Can either move all memories to 'default' workspace or hard delete them.",
702 schema: r#"{
703 "type": "object",
704 "properties": {
705 "workspace": {"type": "string", "description": "Workspace to delete"},
706 "move_to_default": {"type": "boolean", "default": true, "description": "If true, moves memories to 'default' workspace. If false, deletes all memories in the workspace."}
707 },
708 "required": ["workspace"]
709 }"#,
710 annotations: ToolAnnotations::destructive(),
711 },
712 ToolDef {
714 name: "memory_create_daily",
715 description: "Create a daily (ephemeral) memory that auto-expires after the specified TTL. Useful for session context and scratch notes.",
716 schema: r#"{
717 "type": "object",
718 "properties": {
719 "content": {"type": "string", "description": "The content to remember"},
720 "type": {"type": "string", "enum": ["note", "todo", "issue", "decision", "preference", "learning", "context", "credential"], "default": "note"},
721 "tags": {"type": "array", "items": {"type": "string"}, "description": "Tags for categorization"},
722 "metadata": {"type": "object", "description": "Additional metadata as key-value pairs"},
723 "importance": {"type": "number", "minimum": 0, "maximum": 1, "description": "Importance score (0-1)"},
724 "ttl_seconds": {"type": "integer", "default": 86400, "description": "Time-to-live in seconds (default: 24 hours)"},
725 "workspace": {"type": "string", "description": "Workspace to store the memory in (default: 'default')"}
726 },
727 "required": ["content"]
728 }"#,
729 annotations: ToolAnnotations::mutating(),
730 },
731 ToolDef {
732 name: "memory_promote_to_permanent",
733 description: "Promote a daily memory to permanent tier. Clears the expiration and makes the memory permanent.",
734 schema: r#"{
735 "type": "object",
736 "properties": {
737 "id": {"type": "integer", "description": "Memory ID to promote"}
738 },
739 "required": ["id"]
740 }"#,
741 annotations: ToolAnnotations::mutating(),
742 },
743 ToolDef {
745 name: "embedding_cache_stats",
746 description: "Get statistics about the embedding cache (hits, misses, entries, bytes used, hit rate)",
747 schema: r#"{
748 "type": "object",
749 "properties": {}
750 }"#,
751 annotations: ToolAnnotations::read_only(),
752 },
753 ToolDef {
754 name: "embedding_cache_clear",
755 description: "Clear all entries from the embedding cache",
756 schema: r#"{
757 "type": "object",
758 "properties": {}
759 }"#,
760 annotations: ToolAnnotations::destructive(),
761 },
762 ToolDef {
764 name: "session_index",
765 description: "Index a conversation into searchable memory chunks. Uses dual-limiter chunking (messages + characters) with overlap.",
766 schema: r#"{
767 "type": "object",
768 "properties": {
769 "session_id": {"type": "string", "description": "Unique session identifier"},
770 "messages": {
771 "type": "array",
772 "description": "Array of conversation messages",
773 "items": {
774 "type": "object",
775 "properties": {
776 "role": {"type": "string", "description": "Message role (user, assistant, system)"},
777 "content": {"type": "string", "description": "Message content"},
778 "timestamp": {"type": "string", "description": "ISO 8601 timestamp"},
779 "id": {"type": "string", "description": "Optional message ID"}
780 },
781 "required": ["role", "content"]
782 }
783 },
784 "title": {"type": "string", "description": "Optional session title"},
785 "workspace": {"type": "string", "description": "Workspace to store chunks in (default: 'default')"},
786 "agent_id": {"type": "string", "description": "Optional agent identifier"},
787 "max_messages": {"type": "integer", "default": 10, "description": "Max messages per chunk"},
788 "max_chars": {"type": "integer", "default": 8000, "description": "Max characters per chunk"},
789 "overlap": {"type": "integer", "default": 2, "description": "Overlap messages between chunks"},
790 "ttl_days": {"type": "integer", "default": 7, "description": "TTL for transcript chunks in days"}
791 },
792 "required": ["session_id", "messages"]
793 }"#,
794 annotations: ToolAnnotations::mutating(),
795 },
796 ToolDef {
797 name: "session_index_delta",
798 description: "Incrementally index new messages to an existing session. More efficient than full reindex.",
799 schema: r#"{
800 "type": "object",
801 "properties": {
802 "session_id": {"type": "string", "description": "Session to update"},
803 "messages": {
804 "type": "array",
805 "description": "New messages to add",
806 "items": {
807 "type": "object",
808 "properties": {
809 "role": {"type": "string"},
810 "content": {"type": "string"},
811 "timestamp": {"type": "string"},
812 "id": {"type": "string"}
813 },
814 "required": ["role", "content"]
815 }
816 }
817 },
818 "required": ["session_id", "messages"]
819 }"#,
820 annotations: ToolAnnotations::mutating(),
821 },
822 ToolDef {
823 name: "session_get",
824 description: "Get information about an indexed session",
825 schema: r#"{
826 "type": "object",
827 "properties": {
828 "session_id": {"type": "string", "description": "Session ID to retrieve"}
829 },
830 "required": ["session_id"]
831 }"#,
832 annotations: ToolAnnotations::read_only(),
833 },
834 ToolDef {
835 name: "session_list",
836 description: "List indexed sessions with optional workspace filter",
837 schema: r#"{
838 "type": "object",
839 "properties": {
840 "workspace": {"type": "string", "description": "Filter by workspace"},
841 "limit": {"type": "integer", "default": 20, "description": "Maximum sessions to return"}
842 }
843 }"#,
844 annotations: ToolAnnotations::read_only(),
845 },
846 ToolDef {
847 name: "session_delete",
848 description: "Delete a session and all its indexed chunks",
849 schema: r#"{
850 "type": "object",
851 "properties": {
852 "session_id": {"type": "string", "description": "Session to delete"}
853 },
854 "required": ["session_id"]
855 }"#,
856 annotations: ToolAnnotations::destructive(),
857 },
858 ToolDef {
860 name: "identity_create",
861 description: "Create a new identity with canonical ID, display name, and optional aliases",
862 schema: r#"{
863 "type": "object",
864 "properties": {
865 "canonical_id": {"type": "string", "description": "Unique canonical identifier (e.g., 'user:ronaldo', 'org:acme')"},
866 "display_name": {"type": "string", "description": "Human-readable display name"},
867 "entity_type": {"type": "string", "enum": ["person", "organization", "project", "tool", "concept", "other"], "default": "person"},
868 "description": {"type": "string", "description": "Optional description"},
869 "aliases": {"type": "array", "items": {"type": "string"}, "description": "Initial aliases for this identity"},
870 "metadata": {"type": "object", "description": "Additional metadata"}
871 },
872 "required": ["canonical_id", "display_name"]
873 }"#,
874 annotations: ToolAnnotations::mutating(),
875 },
876 ToolDef {
877 name: "identity_get",
878 description: "Get an identity by its canonical ID",
879 schema: r#"{
880 "type": "object",
881 "properties": {
882 "canonical_id": {"type": "string", "description": "Canonical identifier"}
883 },
884 "required": ["canonical_id"]
885 }"#,
886 annotations: ToolAnnotations::read_only(),
887 },
888 ToolDef {
889 name: "identity_update",
890 description: "Update an identity's display name, description, or type",
891 schema: r#"{
892 "type": "object",
893 "properties": {
894 "canonical_id": {"type": "string", "description": "Canonical identifier"},
895 "display_name": {"type": "string", "description": "New display name"},
896 "description": {"type": "string", "description": "New description"},
897 "entity_type": {"type": "string", "enum": ["person", "organization", "project", "tool", "concept", "other"]}
898 },
899 "required": ["canonical_id"]
900 }"#,
901 annotations: ToolAnnotations::mutating(),
902 },
903 ToolDef {
904 name: "identity_delete",
905 description: "Delete an identity and all its aliases",
906 schema: r#"{
907 "type": "object",
908 "properties": {
909 "canonical_id": {"type": "string", "description": "Canonical identifier to delete"}
910 },
911 "required": ["canonical_id"]
912 }"#,
913 annotations: ToolAnnotations::destructive(),
914 },
915 ToolDef {
916 name: "identity_add_alias",
917 description: "Add an alias to an identity. Aliases are normalized (lowercase, trimmed). Conflicts with existing aliases are rejected.",
918 schema: r#"{
919 "type": "object",
920 "properties": {
921 "canonical_id": {"type": "string", "description": "Canonical identifier"},
922 "alias": {"type": "string", "description": "Alias to add"},
923 "source": {"type": "string", "description": "Optional source of the alias (e.g., 'manual', 'extracted')"}
924 },
925 "required": ["canonical_id", "alias"]
926 }"#,
927 annotations: ToolAnnotations::mutating(),
928 },
929 ToolDef {
930 name: "identity_remove_alias",
931 description: "Remove an alias from any identity",
932 schema: r#"{
933 "type": "object",
934 "properties": {
935 "alias": {"type": "string", "description": "Alias to remove"}
936 },
937 "required": ["alias"]
938 }"#,
939 annotations: ToolAnnotations::mutating(),
940 },
941 ToolDef {
942 name: "identity_resolve",
943 description: "Resolve an alias to its canonical identity. Returns the identity if found, null otherwise.",
944 schema: r#"{
945 "type": "object",
946 "properties": {
947 "alias": {"type": "string", "description": "Alias to resolve"}
948 },
949 "required": ["alias"]
950 }"#,
951 annotations: ToolAnnotations::read_only(),
952 },
953 ToolDef {
954 name: "identity_list",
955 description: "List all identities with optional type filter",
956 schema: r#"{
957 "type": "object",
958 "properties": {
959 "entity_type": {"type": "string", "enum": ["person", "organization", "project", "tool", "concept", "other"]},
960 "limit": {"type": "integer", "default": 50}
961 }
962 }"#,
963 annotations: ToolAnnotations::read_only(),
964 },
965 ToolDef {
966 name: "identity_search",
967 description: "Search identities by alias or display name",
968 schema: r#"{
969 "type": "object",
970 "properties": {
971 "query": {"type": "string", "description": "Search query"},
972 "limit": {"type": "integer", "default": 20}
973 },
974 "required": ["query"]
975 }"#,
976 annotations: ToolAnnotations::read_only(),
977 },
978 ToolDef {
979 name: "identity_link",
980 description: "Link an identity to a memory (mark that the identity is mentioned in the memory)",
981 schema: r#"{
982 "type": "object",
983 "properties": {
984 "memory_id": {"type": "integer", "description": "Memory ID"},
985 "canonical_id": {"type": "string", "description": "Identity canonical ID"},
986 "mention_text": {"type": "string", "description": "The text that mentions this identity"}
987 },
988 "required": ["memory_id", "canonical_id"]
989 }"#,
990 annotations: ToolAnnotations::mutating(),
991 },
992 ToolDef {
993 name: "identity_unlink",
994 description: "Remove the link between an identity and a memory",
995 schema: r#"{
996 "type": "object",
997 "properties": {
998 "memory_id": {"type": "integer", "description": "Memory ID"},
999 "canonical_id": {"type": "string", "description": "Identity canonical ID"}
1000 },
1001 "required": ["memory_id", "canonical_id"]
1002 }"#,
1003 annotations: ToolAnnotations::mutating(),
1004 },
1005 ToolDef {
1006 name: "memory_get_identities",
1007 description: "Get all identities (persons, organizations, projects, etc.) linked to a memory. Returns identity details including display name, type, aliases, and mention information.",
1008 schema: r#"{
1009 "type": "object",
1010 "properties": {
1011 "id": {"type": "integer", "description": "Memory ID"}
1012 },
1013 "required": ["id"]
1014 }"#,
1015 annotations: ToolAnnotations::read_only(),
1016 },
1017 ToolDef {
1019 name: "memory_soft_trim",
1020 description: "Intelligently trim memory content while preserving context. Keeps the beginning (head) and end (tail) of content with an ellipsis in the middle. Useful for displaying long content in limited space while keeping important context from both ends.",
1021 schema: r#"{
1022 "type": "object",
1023 "properties": {
1024 "id": {"type": "integer", "description": "Memory ID to trim"},
1025 "max_chars": {"type": "integer", "default": 500, "description": "Maximum characters for trimmed output"},
1026 "head_percent": {"type": "integer", "default": 60, "description": "Percentage of space for the head (0-100)"},
1027 "tail_percent": {"type": "integer", "default": 30, "description": "Percentage of space for the tail (0-100)"},
1028 "ellipsis": {"type": "string", "default": "\n...\n", "description": "Text to insert between head and tail"},
1029 "preserve_words": {"type": "boolean", "default": true, "description": "Avoid breaking in the middle of words"}
1030 },
1031 "required": ["id"]
1032 }"#,
1033 annotations: ToolAnnotations::read_only(),
1034 },
1035 ToolDef {
1036 name: "memory_list_compact",
1037 description: "List memories with compact preview instead of full content. More efficient for browsing/listing UIs. Returns only essential fields and a truncated content preview with metadata about original content length.",
1038 schema: r#"{
1039 "type": "object",
1040 "properties": {
1041 "limit": {"type": "integer", "default": 20, "description": "Maximum memories to return"},
1042 "offset": {"type": "integer", "default": 0, "description": "Pagination offset"},
1043 "tags": {"type": "array", "items": {"type": "string"}, "description": "Filter by tags"},
1044 "memory_type": {"type": "string", "description": "Filter by memory type (preferred field; alias: type)"},
1045 "type": {"type": "string", "description": "Deprecated alias for memory_type"},
1046 "workspace": {"type": "string", "description": "Filter by workspace"},
1047 "tier": {"type": "string", "enum": ["permanent", "daily"], "description": "Filter by tier"},
1048 "sort_by": {"type": "string", "enum": ["created_at", "updated_at", "last_accessed_at", "importance", "access_count"], "default": "created_at"},
1049 "sort_order": {"type": "string", "enum": ["asc", "desc"], "default": "desc"},
1050 "preview_chars": {"type": "integer", "default": 100, "description": "Maximum characters for content preview"}
1051 }
1052 }"#,
1053 annotations: ToolAnnotations::read_only(),
1054 },
1055 ToolDef {
1056 name: "memory_content_stats",
1057 description: "Get content statistics for a memory (character count, word count, line count, sentence count, paragraph count)",
1058 schema: r#"{
1059 "type": "object",
1060 "properties": {
1061 "id": {"type": "integer", "description": "Memory ID"}
1062 },
1063 "required": ["id"]
1064 }"#,
1065 annotations: ToolAnnotations::read_only(),
1066 },
1067 ToolDef {
1069 name: "memory_create_batch",
1070 description: "Create multiple memories in a single operation. More efficient than individual creates for bulk imports.",
1071 schema: r#"{
1072 "type": "object",
1073 "properties": {
1074 "memories": {
1075 "type": "array",
1076 "items": {
1077 "type": "object",
1078 "properties": {
1079 "content": {"type": "string"},
1080 "type": {"type": "string", "enum": ["note", "todo", "issue", "decision", "preference", "learning", "context", "credential"]},
1081 "tags": {"type": "array", "items": {"type": "string"}},
1082 "metadata": {"type": "object"},
1083 "importance": {"type": "number", "minimum": 0, "maximum": 1},
1084 "workspace": {"type": "string"}
1085 },
1086 "required": ["content"]
1087 },
1088 "description": "Array of memories to create"
1089 }
1090 },
1091 "required": ["memories"]
1092 }"#,
1093 annotations: ToolAnnotations::mutating(),
1094 },
1095 ToolDef {
1096 name: "memory_delete_batch",
1097 description: "Delete multiple memories in a single operation.",
1098 schema: r#"{
1099 "type": "object",
1100 "properties": {
1101 "ids": {
1102 "type": "array",
1103 "items": {"type": "integer"},
1104 "description": "Array of memory IDs to delete"
1105 }
1106 },
1107 "required": ["ids"]
1108 }"#,
1109 annotations: ToolAnnotations::destructive(),
1110 },
1111 ToolDef {
1113 name: "memory_tags",
1114 description: "List all tags with usage counts and most recent usage timestamps.",
1115 schema: r#"{
1116 "type": "object",
1117 "properties": {}
1118 }"#,
1119 annotations: ToolAnnotations::read_only(),
1120 },
1121 ToolDef {
1122 name: "memory_tag_hierarchy",
1123 description: "Get tags organized in a hierarchical tree structure. Tags with slashes are treated as paths (e.g., 'project/engram/core').",
1124 schema: r#"{
1125 "type": "object",
1126 "properties": {}
1127 }"#,
1128 annotations: ToolAnnotations::read_only(),
1129 },
1130 ToolDef {
1131 name: "memory_validate_tags",
1132 description: "Validate tag consistency across memories. Reports orphaned tags, unused tags, and suggested normalizations.",
1133 schema: r#"{
1134 "type": "object",
1135 "properties": {}
1136 }"#,
1137 annotations: ToolAnnotations::read_only(),
1138 },
1139 ToolDef {
1141 name: "memory_export",
1142 description: "Export all memories to a JSON-serializable format for backup or migration.",
1143 schema: r#"{
1144 "type": "object",
1145 "properties": {
1146 "workspace": {"type": "string", "description": "Optional: export only from specific workspace"},
1147 "include_embeddings": {"type": "boolean", "default": false, "description": "Include embedding vectors in export (larger file size)"}
1148 }
1149 }"#,
1150 annotations: ToolAnnotations::read_only(),
1151 },
1152 ToolDef {
1153 name: "memory_import",
1154 description: "Import memories from a previously exported JSON format.",
1155 schema: r#"{
1156 "type": "object",
1157 "properties": {
1158 "data": {"type": "object", "description": "The exported data object"},
1159 "skip_duplicates": {"type": "boolean", "default": true, "description": "Skip memories with matching content hash"}
1160 },
1161 "required": ["data"]
1162 }"#,
1163 annotations: ToolAnnotations::mutating(),
1164 },
1165 ToolDef {
1167 name: "memory_rebuild_embeddings",
1168 description: "Rebuild embeddings for all memories that are missing them. Useful after model changes or data recovery.",
1169 schema: r#"{
1170 "type": "object",
1171 "properties": {}
1172 }"#,
1173 annotations: ToolAnnotations::idempotent(),
1174 },
1175 ToolDef {
1176 name: "memory_rebuild_crossrefs",
1177 description: "Rebuild cross-reference links between memories. Re-analyzes all memories to find and create links.",
1178 schema: r#"{
1179 "type": "object",
1180 "properties": {}
1181 }"#,
1182 annotations: ToolAnnotations::idempotent(),
1183 },
1184 ToolDef {
1186 name: "memory_create_section",
1187 description: "Create a section memory for organizing content hierarchically. Sections can have parent sections for nested organization.",
1188 schema: r#"{
1189 "type": "object",
1190 "properties": {
1191 "title": {"type": "string", "description": "Section title"},
1192 "content": {"type": "string", "description": "Section description or content"},
1193 "parent_id": {"type": "integer", "description": "Optional parent section ID for nesting"},
1194 "level": {"type": "integer", "default": 1, "description": "Heading level (1-6)"},
1195 "workspace": {"type": "string", "description": "Workspace for the section"}
1196 },
1197 "required": ["title"]
1198 }"#,
1199 annotations: ToolAnnotations::mutating(),
1200 },
1201 ToolDef {
1202 name: "memory_checkpoint",
1203 description: "Create a checkpoint memory marking a significant point in a session. Useful for session resumption and context restoration.",
1204 schema: r#"{
1205 "type": "object",
1206 "properties": {
1207 "session_id": {"type": "string", "description": "Session identifier"},
1208 "summary": {"type": "string", "description": "Summary of session state at checkpoint"},
1209 "context": {"type": "object", "description": "Additional context data to preserve"},
1210 "workspace": {"type": "string", "description": "Workspace for the checkpoint"}
1211 },
1212 "required": ["session_id", "summary"]
1213 }"#,
1214 annotations: ToolAnnotations::mutating(),
1215 },
1216 ToolDef {
1218 name: "memory_create_episodic",
1219 description: "Create an episodic memory representing an event with temporal context. Use for tracking when things happened and their duration.",
1220 schema: r#"{
1221 "type": "object",
1222 "properties": {
1223 "content": {"type": "string", "description": "Description of the event"},
1224 "event_time": {"type": "string", "format": "date-time", "description": "ISO8601 timestamp when the event occurred"},
1225 "event_duration_seconds": {"type": "integer", "description": "Duration of the event in seconds"},
1226 "tags": {"type": "array", "items": {"type": "string"}, "description": "Tags for categorization"},
1227 "metadata": {"type": "object", "description": "Additional metadata"},
1228 "importance": {"type": "number", "minimum": 0, "maximum": 1, "description": "Importance score (0-1)"},
1229 "workspace": {"type": "string", "description": "Workspace (default: 'default')"}
1230 },
1231 "required": ["content", "event_time"]
1232 }"#,
1233 annotations: ToolAnnotations::mutating(),
1234 },
1235 ToolDef {
1236 name: "memory_create_procedural",
1237 description: "Create a procedural memory representing a learned pattern or workflow. Tracks success/failure to measure effectiveness.",
1238 schema: r#"{
1239 "type": "object",
1240 "properties": {
1241 "content": {"type": "string", "description": "Description of the procedure/workflow"},
1242 "trigger_pattern": {"type": "string", "description": "Pattern that triggers this procedure (e.g., 'When user asks about auth')"},
1243 "tags": {"type": "array", "items": {"type": "string"}, "description": "Tags for categorization"},
1244 "metadata": {"type": "object", "description": "Additional metadata"},
1245 "importance": {"type": "number", "minimum": 0, "maximum": 1, "description": "Importance score (0-1)"},
1246 "workspace": {"type": "string", "description": "Workspace (default: 'default')"}
1247 },
1248 "required": ["content", "trigger_pattern"]
1249 }"#,
1250 annotations: ToolAnnotations::mutating(),
1251 },
1252 ToolDef {
1253 name: "memory_get_timeline",
1254 description: "Query episodic memories by time range. Returns events ordered by event_time.",
1255 schema: r#"{
1256 "type": "object",
1257 "properties": {
1258 "start_time": {"type": "string", "format": "date-time", "description": "Start of time range (ISO8601)"},
1259 "end_time": {"type": "string", "format": "date-time", "description": "End of time range (ISO8601)"},
1260 "workspace": {"type": "string", "description": "Filter by workspace"},
1261 "tags": {"type": "array", "items": {"type": "string"}, "description": "Filter by tags"},
1262 "limit": {"type": "integer", "default": 50, "description": "Maximum results to return"}
1263 }
1264 }"#,
1265 annotations: ToolAnnotations::read_only(),
1266 },
1267 ToolDef {
1268 name: "memory_get_procedures",
1269 description: "List procedural memories (learned patterns/workflows). Optionally filter by trigger pattern.",
1270 schema: r#"{
1271 "type": "object",
1272 "properties": {
1273 "trigger_pattern": {"type": "string", "description": "Filter by trigger pattern (partial match)"},
1274 "workspace": {"type": "string", "description": "Filter by workspace"},
1275 "min_success_rate": {"type": "number", "minimum": 0, "maximum": 1, "description": "Minimum success rate (successes / (successes + failures))"},
1276 "limit": {"type": "integer", "default": 50, "description": "Maximum results to return"}
1277 }
1278 }"#,
1279 annotations: ToolAnnotations::read_only(),
1280 },
1281 ToolDef {
1282 name: "memory_record_procedure_outcome",
1283 description: "Record a success or failure for a procedural memory. Increments the corresponding counter.",
1284 schema: r#"{
1285 "type": "object",
1286 "properties": {
1287 "id": {"type": "integer", "description": "Procedural memory ID"},
1288 "success": {"type": "boolean", "description": "true = success, false = failure"}
1289 },
1290 "required": ["id", "success"]
1291 }"#,
1292 annotations: ToolAnnotations::mutating(),
1293 },
1294 ToolDef {
1295 name: "memory_boost",
1296 description: "Temporarily boost a memory's importance score. The boost can optionally decay over time.",
1297 schema: r#"{
1298 "type": "object",
1299 "properties": {
1300 "id": {"type": "integer", "description": "Memory ID to boost"},
1301 "boost_amount": {"type": "number", "default": 0.2, "description": "Amount to increase importance (0-1)"},
1302 "duration_seconds": {"type": "integer", "description": "Optional: duration before boost decays (omit for permanent boost)"}
1303 },
1304 "required": ["id"]
1305 }"#,
1306 annotations: ToolAnnotations::mutating(),
1307 },
1308 ToolDef {
1310 name: "memory_summarize",
1311 description: "Create a summary of one or more memories. Returns a new Summary-type memory with summary_of_id set.",
1312 schema: r#"{
1313 "type": "object",
1314 "properties": {
1315 "memory_ids": {
1316 "type": "array",
1317 "items": {"type": "integer"},
1318 "description": "IDs of memories to summarize"
1319 },
1320 "summary": {"type": "string", "description": "The summary text (provide this or let the system generate one)"},
1321 "max_length": {"type": "integer", "default": 500, "description": "Maximum length for auto-generated summary"},
1322 "workspace": {"type": "string", "description": "Workspace for the summary memory"},
1323 "tags": {"type": "array", "items": {"type": "string"}, "description": "Tags for the summary memory"}
1324 },
1325 "required": ["memory_ids"]
1326 }"#,
1327 annotations: ToolAnnotations::mutating(),
1328 },
1329 ToolDef {
1330 name: "memory_get_full",
1331 description: "Get the full/original content of a memory. If the memory is a Summary, returns the original content from summary_of_id.",
1332 schema: r#"{
1333 "type": "object",
1334 "properties": {
1335 "id": {"type": "integer", "description": "Memory ID to get full content for"}
1336 },
1337 "required": ["id"]
1338 }"#,
1339 annotations: ToolAnnotations::read_only(),
1340 },
1341 ToolDef {
1342 name: "context_budget_check",
1343 description: "Check token usage of memories against a budget. Returns token counts and suggestions if over budget.",
1344 schema: r#"{
1345 "type": "object",
1346 "properties": {
1347 "memory_ids": {
1348 "type": "array",
1349 "items": {"type": "integer"},
1350 "description": "IDs of memories to check"
1351 },
1352 "model": {
1353 "type": "string",
1354 "description": "Model name for tokenization (gpt-4, gpt-4o, gpt-4o-mini, claude-3-opus, etc.)"
1355 },
1356 "encoding": {
1357 "type": "string",
1358 "description": "Override encoding (cl100k_base, o200k_base). Optional if model is known."
1359 },
1360 "budget": {"type": "integer", "description": "Token budget to check against"}
1361 },
1362 "required": ["memory_ids", "model", "budget"]
1363 }"#,
1364 annotations: ToolAnnotations::read_only(),
1365 },
1366 ToolDef {
1367 name: "memory_archive_old",
1368 description: "Archive old, low-importance memories by creating summaries. Moves originals to archived state.",
1369 schema: r#"{
1370 "type": "object",
1371 "properties": {
1372 "max_age_days": {"type": "integer", "default": 90, "description": "Archive memories older than this many days"},
1373 "max_importance": {"type": "number", "default": 0.5, "description": "Only archive memories with importance below this"},
1374 "min_access_count": {"type": "integer", "default": 5, "description": "Skip memories accessed more than this many times"},
1375 "workspace": {"type": "string", "description": "Limit to specific workspace"},
1376 "dry_run": {"type": "boolean", "default": true, "description": "If true, only report what would be archived"}
1377 }
1378 }"#,
1379 annotations: ToolAnnotations::destructive(),
1380 },
1381 #[cfg(feature = "langfuse")]
1383 ToolDef {
1384 name: "langfuse_connect",
1385 description: "Configure Langfuse connection for observability integration. Stores config in metadata.",
1386 schema: r#"{
1387 "type": "object",
1388 "properties": {
1389 "public_key": {"type": "string", "description": "Langfuse public key (or use LANGFUSE_PUBLIC_KEY env var)"},
1390 "secret_key": {"type": "string", "description": "Langfuse secret key (or use LANGFUSE_SECRET_KEY env var)"},
1391 "base_url": {"type": "string", "default": "https://cloud.langfuse.com", "description": "Langfuse API base URL"}
1392 }
1393 }"#,
1394 annotations: ToolAnnotations::mutating(),
1395 },
1396 #[cfg(feature = "langfuse")]
1397 ToolDef {
1398 name: "langfuse_sync",
1399 description: "Start background sync from Langfuse traces to memories. Returns task_id for status checking.",
1400 schema: r#"{
1401 "type": "object",
1402 "properties": {
1403 "since": {"type": "string", "format": "date-time", "description": "Sync traces since this timestamp (default: 24h ago)"},
1404 "limit": {"type": "integer", "default": 100, "description": "Maximum traces to sync"},
1405 "workspace": {"type": "string", "description": "Workspace to create memories in"},
1406 "dry_run": {"type": "boolean", "default": false, "description": "Preview what would be synced without creating memories"}
1407 }
1408 }"#,
1409 annotations: ToolAnnotations::mutating(),
1410 },
1411 #[cfg(feature = "langfuse")]
1412 ToolDef {
1413 name: "langfuse_sync_status",
1414 description: "Check the status of a Langfuse sync task.",
1415 schema: r#"{
1416 "type": "object",
1417 "properties": {
1418 "task_id": {"type": "string", "description": "Task ID returned from langfuse_sync"}
1419 },
1420 "required": ["task_id"]
1421 }"#,
1422 annotations: ToolAnnotations::read_only(),
1423 },
1424 #[cfg(feature = "langfuse")]
1425 ToolDef {
1426 name: "langfuse_extract_patterns",
1427 description: "Extract patterns from Langfuse traces without saving. Preview mode for pattern discovery.",
1428 schema: r#"{
1429 "type": "object",
1430 "properties": {
1431 "since": {"type": "string", "format": "date-time", "description": "Analyze traces since this timestamp"},
1432 "limit": {"type": "integer", "default": 50, "description": "Maximum traces to analyze"},
1433 "min_confidence": {"type": "number", "default": 0.7, "description": "Minimum confidence for patterns"}
1434 }
1435 }"#,
1436 annotations: ToolAnnotations::read_only(),
1437 },
1438 #[cfg(feature = "langfuse")]
1439 ToolDef {
1440 name: "memory_from_trace",
1441 description: "Create a memory from a specific Langfuse trace ID.",
1442 schema: r#"{
1443 "type": "object",
1444 "properties": {
1445 "trace_id": {"type": "string", "description": "Langfuse trace ID"},
1446 "memory_type": {"type": "string", "enum": ["note", "episodic", "procedural", "learning"], "default": "episodic", "description": "Type of memory to create"},
1447 "workspace": {"type": "string", "description": "Workspace for the memory"},
1448 "tags": {"type": "array", "items": {"type": "string"}, "description": "Additional tags"}
1449 },
1450 "required": ["trace_id"]
1451 }"#,
1452 annotations: ToolAnnotations::mutating(),
1453 },
1454 ToolDef {
1456 name: "search_cache_feedback",
1457 description: "Report feedback on search results quality. Helps tune the adaptive cache threshold.",
1458 schema: r#"{
1459 "type": "object",
1460 "properties": {
1461 "query": {"type": "string", "description": "The search query"},
1462 "positive": {"type": "boolean", "description": "True if results were helpful, false otherwise"},
1463 "workspace": {"type": "string", "description": "Workspace filter used (if any)"}
1464 },
1465 "required": ["query", "positive"]
1466 }"#,
1467 annotations: ToolAnnotations::mutating(),
1468 },
1469 ToolDef {
1470 name: "search_cache_stats",
1471 description: "Get search result cache statistics including hit rate, entry count, and current threshold.",
1472 schema: r#"{
1473 "type": "object",
1474 "properties": {}
1475 }"#,
1476 annotations: ToolAnnotations::read_only(),
1477 },
1478 ToolDef {
1479 name: "search_cache_clear",
1480 description: "Clear the search result cache. Useful after bulk operations.",
1481 schema: r#"{
1482 "type": "object",
1483 "properties": {
1484 "workspace": {"type": "string", "description": "Only clear cache for this workspace (optional)"}
1485 }
1486 }"#,
1487 annotations: ToolAnnotations::destructive(),
1488 },
1489 ToolDef {
1491 name: "lifecycle_status",
1492 description: "Get lifecycle statistics (active/stale/archived counts by workspace).",
1493 schema: r#"{
1494 "type": "object",
1495 "properties": {
1496 "workspace": {"type": "string", "description": "Filter by workspace (optional)"}
1497 }
1498 }"#,
1499 annotations: ToolAnnotations::read_only(),
1500 },
1501 ToolDef {
1502 name: "lifecycle_run",
1503 description: "Manually trigger a lifecycle cycle (mark stale, archive old). Dry run by default.",
1504 schema: r#"{
1505 "type": "object",
1506 "properties": {
1507 "dry_run": {"type": "boolean", "default": true, "description": "Preview changes without applying"},
1508 "workspace": {"type": "string", "description": "Limit to specific workspace"},
1509 "stale_days": {"type": "integer", "default": 30, "description": "Mark memories older than this as stale"},
1510 "archive_days": {"type": "integer", "default": 90, "description": "Archive memories older than this"},
1511 "min_importance": {"type": "number", "default": 0.5, "description": "Only process memories below this importance"}
1512 }
1513 }"#,
1514 annotations: ToolAnnotations::idempotent(),
1515 },
1516 ToolDef {
1517 name: "memory_set_lifecycle",
1518 description: "Manually set the lifecycle state of a memory.",
1519 schema: r#"{
1520 "type": "object",
1521 "properties": {
1522 "id": {"type": "integer", "description": "Memory ID"},
1523 "state": {"type": "string", "enum": ["active", "stale", "archived"], "description": "New lifecycle state"}
1524 },
1525 "required": ["id", "state"]
1526 }"#,
1527 annotations: ToolAnnotations::mutating(),
1528 },
1529 ToolDef {
1530 name: "lifecycle_config",
1531 description: "Get or set lifecycle configuration (intervals, thresholds).",
1532 schema: r#"{
1533 "type": "object",
1534 "properties": {
1535 "stale_days": {"type": "integer", "description": "Days before marking as stale"},
1536 "archive_days": {"type": "integer", "description": "Days before auto-archiving"},
1537 "min_importance": {"type": "number", "description": "Importance threshold for lifecycle"},
1538 "min_access_count": {"type": "integer", "description": "Access count threshold"}
1539 }
1540 }"#,
1541 annotations: ToolAnnotations::read_only(),
1542 },
1543 ToolDef {
1545 name: "retention_policy_set",
1546 description: "Set a retention policy for a workspace. Controls auto-compression, max memory count, and auto-deletion.",
1547 schema: r#"{
1548 "type": "object",
1549 "properties": {
1550 "workspace": {"type": "string", "description": "Workspace name"},
1551 "max_age_days": {"type": "integer", "description": "Hard age limit — auto-delete after this many days"},
1552 "max_memories": {"type": "integer", "description": "Maximum active memories in this workspace"},
1553 "compress_after_days": {"type": "integer", "description": "Auto-compress memories older than this"},
1554 "compress_max_importance": {"type": "number", "description": "Only compress memories with importance <= this (default 0.3)"},
1555 "compress_min_access": {"type": "integer", "description": "Skip compression if access_count >= this (default 3)"},
1556 "auto_delete_after_days": {"type": "integer", "description": "Auto-delete archived memories older than this"},
1557 "exclude_types": {"type": "array", "items": {"type": "string"}, "description": "Memory types exempt from policy (e.g. [\"decision\", \"checkpoint\"])"}
1558 },
1559 "required": ["workspace"]
1560 }"#,
1561 annotations: ToolAnnotations::mutating(),
1562 },
1563 ToolDef {
1564 name: "retention_policy_get",
1565 description: "Get the retention policy for a workspace.",
1566 schema: r#"{
1567 "type": "object",
1568 "properties": {
1569 "workspace": {"type": "string", "description": "Workspace name"}
1570 },
1571 "required": ["workspace"]
1572 }"#,
1573 annotations: ToolAnnotations::read_only(),
1574 },
1575 ToolDef {
1576 name: "retention_policy_list",
1577 description: "List all retention policies across all workspaces.",
1578 schema: r#"{
1579 "type": "object",
1580 "properties": {}
1581 }"#,
1582 annotations: ToolAnnotations::read_only(),
1583 },
1584 ToolDef {
1585 name: "retention_policy_delete",
1586 description: "Delete a retention policy for a workspace.",
1587 schema: r#"{
1588 "type": "object",
1589 "properties": {
1590 "workspace": {"type": "string", "description": "Workspace name"}
1591 },
1592 "required": ["workspace"]
1593 }"#,
1594 annotations: ToolAnnotations::destructive(),
1595 },
1596 ToolDef {
1597 name: "retention_policy_apply",
1598 description: "Apply all retention policies now. Compresses, caps, and deletes per workspace rules.",
1599 schema: r#"{
1600 "type": "object",
1601 "properties": {
1602 "dry_run": {"type": "boolean", "default": false, "description": "Preview what would happen without making changes"}
1603 }
1604 }"#,
1605 annotations: ToolAnnotations::idempotent(),
1606 },
1607 ToolDef {
1609 name: "memory_events_poll",
1610 description: "Poll for memory events (create, update, delete, etc.) since a given point. Useful for syncing and monitoring.",
1611 schema: r#"{
1612 "type": "object",
1613 "properties": {
1614 "since_id": {"type": "integer", "description": "Return events after this event ID"},
1615 "since_time": {"type": "string", "format": "date-time", "description": "Return events after this timestamp (RFC3339)"},
1616 "agent_id": {"type": "string", "description": "Filter events for specific agent"},
1617 "limit": {"type": "integer", "default": 100, "description": "Maximum events to return"}
1618 }
1619 }"#,
1620 annotations: ToolAnnotations::read_only(),
1621 },
1622 ToolDef {
1623 name: "memory_events_clear",
1624 description: "Clear old events from the event log. Helps manage storage for long-running systems.",
1625 schema: r#"{
1626 "type": "object",
1627 "properties": {
1628 "before_id": {"type": "integer", "description": "Delete events before this ID"},
1629 "before_time": {"type": "string", "format": "date-time", "description": "Delete events before this timestamp"},
1630 "keep_recent": {"type": "integer", "description": "Keep only the N most recent events"}
1631 }
1632 }"#,
1633 annotations: ToolAnnotations::destructive(),
1634 },
1635 ToolDef {
1637 name: "sync_version",
1638 description: "Get the current sync version and metadata. Used to check if local data is up-to-date.",
1639 schema: r#"{
1640 "type": "object",
1641 "properties": {}
1642 }"#,
1643 annotations: ToolAnnotations::read_only(),
1644 },
1645 ToolDef {
1646 name: "sync_delta",
1647 description: "Get changes (delta) since a specific version. Returns created, updated, and deleted memories.",
1648 schema: r#"{
1649 "type": "object",
1650 "properties": {
1651 "since_version": {"type": "integer", "description": "Version to get changes from"}
1652 },
1653 "required": ["since_version"]
1654 }"#,
1655 annotations: ToolAnnotations::read_only(),
1656 },
1657 ToolDef {
1658 name: "sync_state",
1659 description: "Get or update sync state for a specific agent. Tracks what each agent has synced.",
1660 schema: r#"{
1661 "type": "object",
1662 "properties": {
1663 "agent_id": {"type": "string", "description": "Agent identifier"},
1664 "update_version": {"type": "integer", "description": "If provided, updates the agent's last synced version"}
1665 },
1666 "required": ["agent_id"]
1667 }"#,
1668 annotations: ToolAnnotations::read_only(),
1669 },
1670 ToolDef {
1671 name: "sync_cleanup",
1672 description: "Clean up old sync data (events, etc.) older than specified days.",
1673 schema: r#"{
1674 "type": "object",
1675 "properties": {
1676 "older_than_days": {"type": "integer", "default": 30, "description": "Delete sync data older than this many days"}
1677 }
1678 }"#,
1679 annotations: ToolAnnotations::destructive(),
1680 },
1681 ToolDef {
1683 name: "memory_share",
1684 description: "Share a memory with another agent. The target agent can poll for shared memories.",
1685 schema: r#"{
1686 "type": "object",
1687 "properties": {
1688 "memory_id": {"type": "integer", "description": "ID of memory to share"},
1689 "from_agent": {"type": "string", "description": "Sender agent identifier"},
1690 "to_agent": {"type": "string", "description": "Recipient agent identifier"},
1691 "message": {"type": "string", "description": "Optional message to include with share"}
1692 },
1693 "required": ["memory_id", "from_agent", "to_agent"]
1694 }"#,
1695 annotations: ToolAnnotations::mutating(),
1696 },
1697 ToolDef {
1698 name: "memory_shared_poll",
1699 description: "Poll for memories shared with this agent.",
1700 schema: r#"{
1701 "type": "object",
1702 "properties": {
1703 "agent_id": {"type": "string", "description": "Agent identifier to check shares for"},
1704 "include_acknowledged": {"type": "boolean", "default": false, "description": "Include already acknowledged shares"}
1705 },
1706 "required": ["agent_id"]
1707 }"#,
1708 annotations: ToolAnnotations::read_only(),
1709 },
1710 ToolDef {
1711 name: "memory_share_ack",
1712 description: "Acknowledge receipt of a shared memory.",
1713 schema: r#"{
1714 "type": "object",
1715 "properties": {
1716 "share_id": {"type": "integer", "description": "Share ID to acknowledge"},
1717 "agent_id": {"type": "string", "description": "Agent acknowledging the share"}
1718 },
1719 "required": ["share_id", "agent_id"]
1720 }"#,
1721 annotations: ToolAnnotations::mutating(),
1722 },
1723 ToolDef {
1725 name: "memory_grant_access",
1726 description: "Grant an agent access to a scope path. Supports read, write, and admin permissions. Access also applies to all descendant scopes.",
1727 schema: r#"{
1728 "type": "object",
1729 "properties": {
1730 "agent_id": {"type": "string", "description": "Agent ID to grant access to"},
1731 "scope_path": {"type": "string", "description": "Scope path to grant access to (e.g. 'global/org:acme')"},
1732 "permissions": {"type": "string", "enum": ["read", "write", "admin"], "default": "read", "description": "Permission level"},
1733 "granted_by": {"type": "string", "description": "Optional: ID of the granting agent"}
1734 },
1735 "required": ["agent_id", "scope_path"]
1736 }"#,
1737 annotations: ToolAnnotations::mutating(),
1738 },
1739 ToolDef {
1740 name: "memory_revoke_access",
1741 description: "Revoke an agent's access to a specific scope path.",
1742 schema: r#"{
1743 "type": "object",
1744 "properties": {
1745 "agent_id": {"type": "string", "description": "Agent ID to revoke access from"},
1746 "scope_path": {"type": "string", "description": "Scope path to revoke access from"}
1747 },
1748 "required": ["agent_id", "scope_path"]
1749 }"#,
1750 annotations: ToolAnnotations::destructive(),
1751 },
1752 ToolDef {
1753 name: "memory_list_grants",
1754 description: "List all scope access grants for a given agent.",
1755 schema: r#"{
1756 "type": "object",
1757 "properties": {
1758 "agent_id": {"type": "string", "description": "Agent ID to list grants for"}
1759 },
1760 "required": ["agent_id"]
1761 }"#,
1762 annotations: ToolAnnotations::read_only(),
1763 },
1764 ToolDef {
1765 name: "memory_check_access",
1766 description: "Check whether an agent has a required permission level on a scope path (including ancestor grants).",
1767 schema: r#"{
1768 "type": "object",
1769 "properties": {
1770 "agent_id": {"type": "string", "description": "Agent ID to check"},
1771 "scope_path": {"type": "string", "description": "Scope path to check access for"},
1772 "permissions": {"type": "string", "enum": ["read", "write", "admin"], "default": "read", "description": "Required permission level"}
1773 },
1774 "required": ["agent_id", "scope_path"]
1775 }"#,
1776 annotations: ToolAnnotations::read_only(),
1777 },
1778 ToolDef {
1780 name: "memory_search_by_identity",
1781 description: "Search memories by identity (person, entity, or alias). Finds all mentions of a specific identity across memories.",
1782 schema: r#"{
1783 "type": "object",
1784 "properties": {
1785 "identity": {"type": "string", "description": "Identity name or alias to search for"},
1786 "workspace": {"type": "string", "description": "Optional: limit search to specific workspace"},
1787 "limit": {"type": "integer", "default": 50, "description": "Maximum results to return"}
1788 },
1789 "required": ["identity"]
1790 }"#,
1791 annotations: ToolAnnotations::mutating(),
1792 },
1793 ToolDef {
1794 name: "memory_session_search",
1795 description: "Search within session transcript chunks. Useful for finding content from past conversations.",
1796 schema: r#"{
1797 "type": "object",
1798 "properties": {
1799 "query": {"type": "string", "description": "Search query"},
1800 "session_id": {"type": "string", "description": "Optional: limit to specific session"},
1801 "workspace": {"type": "string", "description": "Optional: limit to specific workspace"},
1802 "limit": {"type": "integer", "default": 20, "description": "Maximum results to return"}
1803 },
1804 "required": ["query"]
1805 }"#,
1806 annotations: ToolAnnotations::mutating(),
1807 },
1808 ToolDef {
1810 name: "memory_upload_image",
1811 description: "Upload an image file and attach it to a memory. The image will be stored locally and linked to the memory's metadata.",
1812 schema: r#"{
1813 "type": "object",
1814 "properties": {
1815 "memory_id": {"type": "integer", "description": "ID of the memory to attach the image to"},
1816 "file_path": {"type": "string", "description": "Path to the image file to upload"},
1817 "image_index": {"type": "integer", "default": 0, "description": "Index for ordering multiple images (0-based)"},
1818 "caption": {"type": "string", "description": "Optional caption for the image"}
1819 },
1820 "required": ["memory_id", "file_path"]
1821 }"#,
1822 annotations: ToolAnnotations::mutating(),
1823 },
1824 ToolDef {
1825 name: "memory_migrate_images",
1826 description: "Migrate existing base64-encoded images in memories to file storage. Scans all memories and uploads any embedded data URIs to storage, replacing them with file references.",
1827 schema: r#"{
1828 "type": "object",
1829 "properties": {
1830 "dry_run": {"type": "boolean", "default": false, "description": "If true, only report what would be migrated without making changes"}
1831 }
1832 }"#,
1833 annotations: ToolAnnotations::idempotent(),
1834 },
1835 ToolDef {
1837 name: "memory_suggest_tags",
1838 description: "Suggest tags for a memory based on AI content analysis. Uses pattern matching, keyword extraction, and structure detection to suggest relevant tags with confidence scores.",
1839 schema: r#"{
1840 "type": "object",
1841 "properties": {
1842 "id": {"type": "integer", "description": "Memory ID to analyze (alternative to content)"},
1843 "memory_id": {"type": "integer", "description": "Memory ID to analyze (alias for id)"},
1844 "content": {"type": "string", "description": "Content to analyze (alternative to id/memory_id)"},
1845 "type": {"type": "string", "enum": ["note", "todo", "issue", "decision", "preference", "learning", "context", "credential"], "description": "Memory type (used when providing content directly)"},
1846 "existing_tags": {"type": "array", "items": {"type": "string"}, "description": "Tags already on the memory (excluded from suggestions)"},
1847 "min_confidence": {"type": "number", "minimum": 0, "maximum": 1, "default": 0.5, "description": "Minimum confidence threshold for suggestions"},
1848 "max_tags": {"type": "integer", "default": 5, "description": "Maximum number of tags to suggest"},
1849 "enable_patterns": {"type": "boolean", "default": true, "description": "Use pattern-based tagging"},
1850 "enable_keywords": {"type": "boolean", "default": true, "description": "Use keyword-based tagging"},
1851 "enable_entities": {"type": "boolean", "default": true, "description": "Use entity-based tagging"},
1852 "enable_type_tags": {"type": "boolean", "default": true, "description": "Add tags based on memory type"},
1853 "keyword_mappings": {"type": "object", "description": "Custom keyword-to-tag mappings (e.g., {\"ibvi\": \"project/ibvi\"})"}
1854 }
1855 }"#,
1856 annotations: ToolAnnotations::read_only(),
1857 },
1858 ToolDef {
1859 name: "memory_auto_tag",
1860 description: "Automatically suggest and optionally apply tags to a memory. Analyzes content using AI heuristics and can merge suggested tags with existing ones.",
1861 schema: r#"{
1862 "type": "object",
1863 "properties": {
1864 "id": {"type": "integer", "description": "Memory ID to auto-tag"},
1865 "memory_id": {"type": "integer", "description": "Memory ID (alias for id)"},
1866 "apply": {"type": "boolean", "default": false, "description": "If true, apply the suggested tags to the memory. If false, only return suggestions."},
1867 "merge": {"type": "boolean", "default": true, "description": "If true and apply=true, merge with existing tags. If false, replace existing tags."},
1868 "min_confidence": {"type": "number", "minimum": 0, "maximum": 1, "default": 0.5, "description": "Minimum confidence threshold"},
1869 "max_tags": {"type": "integer", "default": 5, "description": "Maximum tags to suggest/apply"},
1870 "keyword_mappings": {"type": "object", "description": "Custom keyword-to-tag mappings"}
1871 },
1872 "required": ["id"]
1873 }"#,
1874 annotations: ToolAnnotations::mutating(),
1875 },
1876 ToolDef {
1878 name: "salience_get",
1879 description: "Get the salience score for a memory. Returns recency, frequency, importance, and feedback components with the combined score and lifecycle state.",
1880 schema: r#"{
1881 "type": "object",
1882 "properties": {
1883 "id": {"type": "integer", "description": "Memory ID to get salience for"},
1884 "feedback_signal": {"type": "number", "minimum": -1, "maximum": 1, "default": 0, "description": "Optional feedback signal (-1 to 1) to include in calculation"}
1885 },
1886 "required": ["id"]
1887 }"#,
1888 annotations: ToolAnnotations::read_only(),
1889 },
1890 ToolDef {
1891 name: "salience_set_importance",
1892 description: "Set the importance score for a memory. This is the static importance component of salience.",
1893 schema: r#"{
1894 "type": "object",
1895 "properties": {
1896 "id": {"type": "integer", "description": "Memory ID"},
1897 "importance": {"type": "number", "minimum": 0, "maximum": 1, "description": "Importance score (0-1)"}
1898 },
1899 "required": ["id", "importance"]
1900 }"#,
1901 annotations: ToolAnnotations::mutating(),
1902 },
1903 ToolDef {
1904 name: "salience_boost",
1905 description: "Boost a memory's salience score temporarily or permanently. Useful for marking memories as contextually relevant.",
1906 schema: r#"{
1907 "type": "object",
1908 "properties": {
1909 "id": {"type": "integer", "description": "Memory ID to boost"},
1910 "boost_amount": {"type": "number", "minimum": 0, "maximum": 1, "default": 0.2, "description": "Amount to boost (0-1)"},
1911 "reason": {"type": "string", "description": "Optional reason for boosting"}
1912 },
1913 "required": ["id"]
1914 }"#,
1915 annotations: ToolAnnotations::mutating(),
1916 },
1917 ToolDef {
1918 name: "salience_demote",
1919 description: "Demote a memory's salience score. Useful for marking memories as less relevant.",
1920 schema: r#"{
1921 "type": "object",
1922 "properties": {
1923 "id": {"type": "integer", "description": "Memory ID to demote"},
1924 "demote_amount": {"type": "number", "minimum": 0, "maximum": 1, "default": 0.2, "description": "Amount to demote (0-1)"},
1925 "reason": {"type": "string", "description": "Optional reason for demoting"}
1926 },
1927 "required": ["id"]
1928 }"#,
1929 annotations: ToolAnnotations::mutating(),
1930 },
1931 ToolDef {
1932 name: "salience_decay_run",
1933 description: "Run temporal decay on all memories. Updates lifecycle states (Active → Stale → Archived) based on salience scores.",
1934 schema: r#"{
1935 "type": "object",
1936 "properties": {
1937 "dry_run": {"type": "boolean", "default": false, "description": "If true, compute changes without persisting updates"},
1938 "record_history": {"type": "boolean", "default": true, "description": "Record salience history entries while updating"},
1939 "workspace": {"type": "string", "description": "Limit to specific workspace"},
1940 "stale_threshold_days": {"type": "integer", "minimum": 1, "description": "Days of inactivity before marking stale"},
1941 "archive_threshold_days": {"type": "integer", "minimum": 1, "description": "Days of inactivity before suggesting archive"}
1942 }
1943 }"#,
1944 annotations: ToolAnnotations::destructive(),
1945 },
1946 ToolDef {
1947 name: "salience_stats",
1948 description: "Get salience statistics across all memories. Returns distribution, percentiles, and state counts.",
1949 schema: r#"{
1950 "type": "object",
1951 "properties": {
1952 "workspace": {"type": "string", "description": "Limit to specific workspace"}
1953 }
1954 }"#,
1955 annotations: ToolAnnotations::read_only(),
1956 },
1957 ToolDef {
1958 name: "salience_history",
1959 description: "Get salience score history for a memory. Shows how salience has changed over time.",
1960 schema: r#"{
1961 "type": "object",
1962 "properties": {
1963 "id": {"type": "integer", "description": "Memory ID"},
1964 "limit": {"type": "integer", "default": 50, "description": "Maximum history entries to return"}
1965 },
1966 "required": ["id"]
1967 }"#,
1968 annotations: ToolAnnotations::read_only(),
1969 },
1970 ToolDef {
1971 name: "salience_top",
1972 description: "Get top memories by salience score. Useful for context injection.",
1973 schema: r#"{
1974 "type": "object",
1975 "properties": {
1976 "limit": {"type": "integer", "default": 20, "description": "Maximum memories to return"},
1977 "workspace": {"type": "string", "description": "Limit to specific workspace"},
1978 "min_score": {"type": "number", "minimum": 0, "maximum": 1, "description": "Minimum salience score"},
1979 "memory_type": {"type": "string", "description": "Filter by memory type"}
1980 }
1981 }"#,
1982 annotations: ToolAnnotations::read_only(),
1983 },
1984 ToolDef {
1986 name: "session_context_create",
1987 description: "Create a new session context for tracking related memories during a conversation or task.",
1988 schema: r#"{
1989 "type": "object",
1990 "properties": {
1991 "name": {"type": "string", "description": "Session name"},
1992 "description": {"type": "string", "description": "Session description"},
1993 "workspace": {"type": "string", "description": "Workspace for the session"},
1994 "metadata": {"type": "object", "description": "Additional session metadata"}
1995 },
1996 "required": ["name"]
1997 }"#,
1998 annotations: ToolAnnotations::mutating(),
1999 },
2000 ToolDef {
2001 name: "session_context_add_memory",
2002 description: "Add a memory to a session context with relevance score and role.",
2003 schema: r#"{
2004 "type": "object",
2005 "properties": {
2006 "session_id": {"type": "string", "description": "Session ID"},
2007 "memory_id": {"type": "integer", "description": "Memory ID to add"},
2008 "relevance_score": {"type": "number", "minimum": 0, "maximum": 1, "default": 1.0, "description": "How relevant this memory is to the session"},
2009 "context_role": {"type": "string", "enum": ["referenced", "created", "updated", "pinned"], "default": "referenced", "description": "Role of the memory in the session"}
2010 },
2011 "required": ["session_id", "memory_id"]
2012 }"#,
2013 annotations: ToolAnnotations::mutating(),
2014 },
2015 ToolDef {
2016 name: "session_context_remove_memory",
2017 description: "Remove a memory from a session context.",
2018 schema: r#"{
2019 "type": "object",
2020 "properties": {
2021 "session_id": {"type": "string", "description": "Session ID"},
2022 "memory_id": {"type": "integer", "description": "Memory ID to remove"}
2023 },
2024 "required": ["session_id", "memory_id"]
2025 }"#,
2026 annotations: ToolAnnotations::mutating(),
2027 },
2028 ToolDef {
2029 name: "session_context_get",
2030 description: "Get a session context with its linked memories.",
2031 schema: r#"{
2032 "type": "object",
2033 "properties": {
2034 "session_id": {"type": "string", "description": "Session ID"}
2035 },
2036 "required": ["session_id"]
2037 }"#,
2038 annotations: ToolAnnotations::read_only(),
2039 },
2040 ToolDef {
2041 name: "session_context_list",
2042 description: "List all session contexts with optional filtering.",
2043 schema: r#"{
2044 "type": "object",
2045 "properties": {
2046 "workspace": {"type": "string", "description": "Filter by workspace"},
2047 "active_only": {"type": "boolean", "default": false, "description": "Only return active sessions"},
2048 "limit": {"type": "integer", "default": 50, "description": "Maximum sessions to return"},
2049 "offset": {"type": "integer", "default": 0, "description": "Offset for pagination"}
2050 }
2051 }"#,
2052 annotations: ToolAnnotations::read_only(),
2053 },
2054 ToolDef {
2055 name: "session_context_search",
2056 description: "Search memories within a specific session context.",
2057 schema: r#"{
2058 "type": "object",
2059 "properties": {
2060 "session_id": {"type": "string", "description": "Session ID to search within"},
2061 "query": {"type": "string", "description": "Search query"},
2062 "limit": {"type": "integer", "default": 20, "description": "Maximum results"}
2063 },
2064 "required": ["session_id", "query"]
2065 }"#,
2066 annotations: ToolAnnotations::read_only(),
2067 },
2068 ToolDef {
2069 name: "session_context_update_summary",
2070 description: "Update the summary of a session context.",
2071 schema: r#"{
2072 "type": "object",
2073 "properties": {
2074 "session_id": {"type": "string", "description": "Session ID"},
2075 "summary": {"type": "string", "description": "New session summary"}
2076 },
2077 "required": ["session_id", "summary"]
2078 }"#,
2079 annotations: ToolAnnotations::mutating(),
2080 },
2081 ToolDef {
2082 name: "session_context_end",
2083 description: "End a session context, marking it as inactive.",
2084 schema: r#"{
2085 "type": "object",
2086 "properties": {
2087 "session_id": {"type": "string", "description": "Session ID to end"},
2088 "summary": {"type": "string", "description": "Optional final summary"}
2089 },
2090 "required": ["session_id"]
2091 }"#,
2092 annotations: ToolAnnotations::mutating(),
2093 },
2094 ToolDef {
2095 name: "session_context_export",
2096 description: "Export a session context with all its memories for archival or sharing.",
2097 schema: r#"{
2098 "type": "object",
2099 "properties": {
2100 "session_id": {"type": "string", "description": "Session ID to export"},
2101 "include_content": {"type": "boolean", "default": true, "description": "Include full memory content"},
2102 "format": {"type": "string", "enum": ["json", "markdown"], "default": "json", "description": "Export format"}
2103 },
2104 "required": ["session_id"]
2105 }"#,
2106 annotations: ToolAnnotations::read_only(),
2107 },
2108 ToolDef {
2110 name: "quality_score",
2111 description: "Get the quality score for a memory with detailed breakdown of clarity, completeness, freshness, consistency, and source trust components.",
2112 schema: r#"{
2113 "type": "object",
2114 "properties": {
2115 "id": {"type": "integer", "description": "Memory ID to score"}
2116 },
2117 "required": ["id"]
2118 }"#,
2119 annotations: ToolAnnotations::read_only(),
2120 },
2121 ToolDef {
2122 name: "quality_report",
2123 description: "Generate a comprehensive quality report for a workspace. Includes quality distribution, top issues, conflict and duplicate counts.",
2124 schema: r#"{
2125 "type": "object",
2126 "properties": {
2127 "workspace": {"type": "string", "description": "Workspace to analyze (default: 'default')"}
2128 }
2129 }"#,
2130 annotations: ToolAnnotations::read_only(),
2131 },
2132 ToolDef {
2133 name: "quality_find_duplicates",
2134 description: "Find near-duplicate memories using text similarity. Returns pairs of similar memories above the threshold.",
2135 schema: r#"{
2136 "type": "object",
2137 "properties": {
2138 "threshold": {"type": "number", "minimum": 0, "maximum": 1, "default": 0.85, "description": "Similarity threshold (0-1)"},
2139 "limit": {"type": "integer", "default": 100, "description": "Maximum memories to compare"}
2140 }
2141 }"#,
2142 annotations: ToolAnnotations::read_only(),
2143 },
2144 ToolDef {
2145 name: "quality_get_duplicates",
2146 description: "Get pending duplicate candidates that need review.",
2147 schema: r#"{
2148 "type": "object",
2149 "properties": {
2150 "limit": {"type": "integer", "default": 50, "description": "Maximum duplicates to return"}
2151 }
2152 }"#,
2153 annotations: ToolAnnotations::read_only(),
2154 },
2155 ToolDef {
2156 name: "quality_find_conflicts",
2157 description: "Detect conflicts for a memory against existing memories. Finds contradictions, staleness, and semantic overlaps.",
2158 schema: r#"{
2159 "type": "object",
2160 "properties": {
2161 "id": {"type": "integer", "description": "Memory ID to check for conflicts"}
2162 },
2163 "required": ["id"]
2164 }"#,
2165 annotations: ToolAnnotations::read_only(),
2166 },
2167 ToolDef {
2168 name: "quality_get_conflicts",
2169 description: "Get unresolved conflicts that need attention.",
2170 schema: r#"{
2171 "type": "object",
2172 "properties": {
2173 "limit": {"type": "integer", "default": 50, "description": "Maximum conflicts to return"}
2174 }
2175 }"#,
2176 annotations: ToolAnnotations::read_only(),
2177 },
2178 ToolDef {
2179 name: "quality_resolve_conflict",
2180 description: "Resolve a conflict between memories. Options: keep_a, keep_b, merge, keep_both, delete_both, false_positive.",
2181 schema: r#"{
2182 "type": "object",
2183 "properties": {
2184 "conflict_id": {"type": "integer", "description": "Conflict ID to resolve"},
2185 "resolution": {"type": "string", "enum": ["keep_a", "keep_b", "merge", "keep_both", "delete_both", "false_positive"], "description": "How to resolve the conflict"},
2186 "notes": {"type": "string", "description": "Optional notes about the resolution"}
2187 },
2188 "required": ["conflict_id", "resolution"]
2189 }"#,
2190 annotations: ToolAnnotations::destructive(),
2191 },
2192 ToolDef {
2193 name: "quality_source_trust",
2194 description: "Get or update trust score for a source type. Higher trust means memories from this source are weighted more in quality calculations.",
2195 schema: r#"{
2196 "type": "object",
2197 "properties": {
2198 "source_type": {"type": "string", "description": "Source type (user, seed, extraction, inference, external)"},
2199 "source_identifier": {"type": "string", "description": "Optional specific source identifier"},
2200 "trust_score": {"type": "number", "minimum": 0, "maximum": 1, "description": "New trust score (omit to just get current score)"},
2201 "notes": {"type": "string", "description": "Notes about this source"}
2202 },
2203 "required": ["source_type"]
2204 }"#,
2205 annotations: ToolAnnotations::read_only(),
2206 },
2207 ToolDef {
2208 name: "quality_improve",
2209 description: "Get suggestions for improving a memory's quality. Returns actionable recommendations.",
2210 schema: r#"{
2211 "type": "object",
2212 "properties": {
2213 "id": {"type": "integer", "description": "Memory ID to analyze"}
2214 },
2215 "required": ["id"]
2216 }"#,
2217 annotations: ToolAnnotations::mutating(),
2218 },
2219 #[cfg(feature = "meilisearch")]
2221 ToolDef {
2222 name: "meilisearch_search",
2223 description: "Search memories using Meilisearch (typo-tolerant, fast full-text). Requires Meilisearch to be configured. Falls back to hybrid search if unavailable.",
2224 schema: r#"{
2225 "type": "object",
2226 "properties": {
2227 "query": {"type": "string", "description": "Search query text"},
2228 "limit": {"type": "integer", "default": 20, "description": "Maximum results to return"},
2229 "offset": {"type": "integer", "default": 0, "description": "Number of results to skip"},
2230 "workspace": {"type": "string", "description": "Filter by workspace"},
2231 "tags": {"type": "array", "items": {"type": "string"}, "description": "Filter by tags (AND logic)"},
2232 "memory_type": {"type": "string", "description": "Filter by memory type"}
2233 },
2234 "required": ["query"]
2235 }"#,
2236 annotations: ToolAnnotations::read_only(),
2237 },
2238 #[cfg(feature = "meilisearch")]
2239 ToolDef {
2240 name: "meilisearch_reindex",
2241 description: "Trigger a full re-sync from SQLite to Meilisearch. Use after bulk imports or if the index is out of sync.",
2242 schema: r#"{
2243 "type": "object",
2244 "properties": {}
2245 }"#,
2246 annotations: ToolAnnotations::idempotent(),
2247 },
2248 #[cfg(feature = "meilisearch")]
2249 ToolDef {
2250 name: "meilisearch_status",
2251 description: "Get Meilisearch index status including document count, indexing state, and health.",
2252 schema: r#"{
2253 "type": "object",
2254 "properties": {}
2255 }"#,
2256 annotations: ToolAnnotations::read_only(),
2257 },
2258 #[cfg(feature = "meilisearch")]
2259 ToolDef {
2260 name: "meilisearch_config",
2261 description: "Show current Meilisearch configuration (URL, sync interval, enabled status).",
2262 schema: r#"{
2263 "type": "object",
2264 "properties": {}
2265 }"#,
2266 annotations: ToolAnnotations::read_only(),
2267 },
2268 ToolDef {
2270 name: "agent_register",
2271 description: "Register an AI agent with capabilities and namespace isolation. Upserts if agent_id already exists.",
2272 schema: r#"{
2273 "type": "object",
2274 "properties": {
2275 "agent_id": {"type": "string", "description": "Unique identifier for the agent"},
2276 "display_name": {"type": "string", "description": "Human-readable name (defaults to agent_id)"},
2277 "capabilities": {"type": "array", "items": {"type": "string"}, "description": "List of capabilities (e.g., 'search', 'create', 'analyze')"},
2278 "namespaces": {"type": "array", "items": {"type": "string"}, "description": "Namespaces the agent operates in (default: ['default'])"},
2279 "metadata": {"type": "object", "description": "Additional metadata as key-value pairs"}
2280 },
2281 "required": ["agent_id"]
2282 }"#,
2283 annotations: ToolAnnotations::mutating(),
2284 },
2285 ToolDef {
2286 name: "agent_deregister",
2287 description: "Deregister an AI agent (soft delete — sets status to 'inactive').",
2288 schema: r#"{
2289 "type": "object",
2290 "properties": {
2291 "agent_id": {"type": "string", "description": "ID of the agent to deregister"}
2292 },
2293 "required": ["agent_id"]
2294 }"#,
2295 annotations: ToolAnnotations::destructive(),
2296 },
2297 ToolDef {
2298 name: "agent_heartbeat",
2299 description: "Update an agent's heartbeat timestamp to indicate it is still alive.",
2300 schema: r#"{
2301 "type": "object",
2302 "properties": {
2303 "agent_id": {"type": "string", "description": "ID of the agent sending heartbeat"}
2304 },
2305 "required": ["agent_id"]
2306 }"#,
2307 annotations: ToolAnnotations::mutating(),
2308 },
2309 ToolDef {
2310 name: "agent_list",
2311 description: "List registered agents, optionally filtered by status or namespace.",
2312 schema: r#"{
2313 "type": "object",
2314 "properties": {
2315 "status": {"type": "string", "enum": ["active", "inactive"], "description": "Filter by agent status"},
2316 "namespace": {"type": "string", "description": "Filter by namespace (returns agents that include this namespace)"}
2317 }
2318 }"#,
2319 annotations: ToolAnnotations::read_only(),
2320 },
2321 ToolDef {
2322 name: "agent_get",
2323 description: "Get details of a specific registered agent by ID.",
2324 schema: r#"{
2325 "type": "object",
2326 "properties": {
2327 "agent_id": {"type": "string", "description": "ID of the agent to retrieve"}
2328 },
2329 "required": ["agent_id"]
2330 }"#,
2331 annotations: ToolAnnotations::read_only(),
2332 },
2333 ToolDef {
2334 name: "agent_capabilities",
2335 description: "Update the capabilities list of a registered agent.",
2336 schema: r#"{
2337 "type": "object",
2338 "properties": {
2339 "agent_id": {"type": "string", "description": "ID of the agent to update"},
2340 "capabilities": {"type": "array", "items": {"type": "string"}, "description": "New capabilities list (replaces existing)"}
2341 },
2342 "required": ["agent_id", "capabilities"]
2343 }"#,
2344 annotations: ToolAnnotations::mutating(),
2345 },
2346
2347 #[cfg(feature = "agent-portability")]
2349 ToolDef {
2350 name: "snapshot_create",
2351 description: "Create a portable .egm snapshot of memories filtered by workspace, tags, date range, or importance. Optionally encrypt with AES-256-GCM or sign with Ed25519.",
2352 schema: r#"{
2353 "type": "object",
2354 "properties": {
2355 "output_path": {"type": "string", "description": "File path for the .egm snapshot"},
2356 "workspace": {"type": "string", "description": "Filter by workspace"},
2357 "tags": {"type": "array", "items": {"type": "string"}, "description": "Filter by tags"},
2358 "importance_min": {"type": "number", "description": "Minimum importance score"},
2359 "memory_types": {"type": "array", "items": {"type": "string"}, "description": "Filter by memory types"},
2360 "description": {"type": "string", "description": "Human-readable description"},
2361 "creator": {"type": "string", "description": "Creator name"},
2362 "encrypt_key": {"type": "string", "description": "Hex-encoded 32-byte AES key"},
2363 "sign_key": {"type": "string", "description": "Hex-encoded 32-byte Ed25519 secret key"}
2364 },
2365 "required": ["output_path"]
2366 }"#,
2367 annotations: ToolAnnotations::mutating(),
2368 },
2369 #[cfg(feature = "agent-portability")]
2370 ToolDef {
2371 name: "snapshot_load",
2372 description: "Load a .egm snapshot into the memory store. Strategies: merge (skip duplicates), replace (clear workspace first), isolate (new workspace), dry_run (preview only).",
2373 schema: r#"{
2374 "type": "object",
2375 "properties": {
2376 "path": {"type": "string", "description": "Path to .egm file"},
2377 "strategy": {"type": "string", "enum": ["merge", "replace", "isolate", "dry_run"], "description": "Load strategy"},
2378 "target_workspace": {"type": "string", "description": "Target workspace (defaults to snapshot's workspace)"},
2379 "decrypt_key": {"type": "string", "description": "Hex-encoded 32-byte AES key for encrypted snapshots"}
2380 },
2381 "required": ["path", "strategy"]
2382 }"#,
2383 annotations: ToolAnnotations::mutating(),
2384 },
2385 #[cfg(feature = "agent-portability")]
2386 ToolDef {
2387 name: "snapshot_inspect",
2388 description: "Inspect a .egm snapshot without loading it. Returns manifest, file list, and size.",
2389 schema: r#"{
2390 "type": "object",
2391 "properties": {
2392 "path": {"type": "string", "description": "Path to .egm file"}
2393 },
2394 "required": ["path"]
2395 }"#,
2396 annotations: ToolAnnotations::read_only(),
2397 },
2398
2399 #[cfg(feature = "agent-portability")]
2401 ToolDef {
2402 name: "attestation_log",
2403 description: "Log a document ingestion with cryptographic attestation. Creates a chained record proving the document was processed.",
2404 schema: r#"{
2405 "type": "object",
2406 "properties": {
2407 "content": {"type": "string", "description": "Document content to attest"},
2408 "document_name": {"type": "string", "description": "Name of the document"},
2409 "agent_id": {"type": "string", "description": "ID of the attesting agent"},
2410 "memory_ids": {"type": "array", "items": {"type": "integer"}, "description": "IDs of memories created from this document"},
2411 "sign_key": {"type": "string", "description": "Hex-encoded 32-byte Ed25519 secret key"}
2412 },
2413 "required": ["content", "document_name"]
2414 }"#,
2415 annotations: ToolAnnotations::mutating(),
2416 },
2417 #[cfg(feature = "agent-portability")]
2418 ToolDef {
2419 name: "attestation_verify",
2420 description: "Verify whether a document has been attested (ingested and recorded).",
2421 schema: r#"{
2422 "type": "object",
2423 "properties": {
2424 "content": {"type": "string", "description": "Document content to verify"}
2425 },
2426 "required": ["content"]
2427 }"#,
2428 annotations: ToolAnnotations::read_only(),
2429 },
2430 #[cfg(feature = "agent-portability")]
2431 ToolDef {
2432 name: "attestation_chain_verify",
2433 description: "Verify the integrity of the entire attestation chain. Returns valid, broken (with location), or empty.",
2434 schema: r#"{
2435 "type": "object",
2436 "properties": {}
2437 }"#,
2438 annotations: ToolAnnotations::read_only(),
2439 },
2440 #[cfg(feature = "agent-portability")]
2441 ToolDef {
2442 name: "attestation_list",
2443 description: "List attestation records with optional filters. Supports JSON, CSV, and Merkle proof export formats.",
2444 schema: r#"{
2445 "type": "object",
2446 "properties": {
2447 "limit": {"type": "integer", "description": "Maximum records to return", "default": 50},
2448 "offset": {"type": "integer", "description": "Number of records to skip", "default": 0},
2449 "agent_id": {"type": "string", "description": "Filter by agent ID"},
2450 "document_name": {"type": "string", "description": "Filter by document name"},
2451 "export_format": {"type": "string", "enum": ["json", "csv", "merkle_proof"], "description": "Export format"}
2452 }
2453 }"#,
2454 annotations: ToolAnnotations::read_only(),
2455 },
2456
2457 #[cfg(feature = "duckdb-graph")]
2459 ToolDef {
2460 name: "memory_graph_path",
2461 description: "Finds how two entities are connected in the knowledge graph via DuckDB OLAP engine. Discovers hidden relationships across multiple hops using recursive path-finding.",
2462 schema: r#"{
2463 "type": "object",
2464 "properties": {
2465 "scope": {"type": "string", "description": "Tenant scope prefix, e.g., 'global/org/user'"},
2466 "source_id": {"type": "integer", "description": "Starting node ID"},
2467 "target_id": {"type": "integer", "description": "Target node ID"},
2468 "max_depth": {"type": "integer", "description": "Maximum hops to traverse (default: 4, max: 10)", "default": 4}
2469 },
2470 "required": ["scope", "source_id", "target_id"]
2471 }"#,
2472 annotations: ToolAnnotations {
2473 read_only_hint: Some(true),
2474 destructive_hint: None,
2475 idempotent_hint: Some(true),
2476 open_world_hint: None,
2477 },
2478 },
2479 #[cfg(feature = "duckdb-graph")]
2480 ToolDef {
2481 name: "memory_temporal_snapshot",
2482 description: "Retrieves the exact facts and relationships that were true at a specific historical point in time. Uses DuckDB OLAP engine for fast columnar scans over temporal edges.",
2483 schema: r#"{
2484 "type": "object",
2485 "properties": {
2486 "scope": {"type": "string", "description": "Tenant scope prefix"},
2487 "timestamp": {"type": "string", "description": "ISO-8601 timestamp for the point-in-time query"}
2488 },
2489 "required": ["scope", "timestamp"]
2490 }"#,
2491 annotations: ToolAnnotations {
2492 read_only_hint: Some(true),
2493 destructive_hint: None,
2494 idempotent_hint: Some(true),
2495 open_world_hint: None,
2496 },
2497 },
2498 #[cfg(feature = "duckdb-graph")]
2499 ToolDef {
2500 name: "memory_scope_snapshot",
2501 description: "Compares the knowledge graph between two timestamps, showing what relationships were added, removed, or changed. Uses DuckDB OLAP engine for efficient temporal diff.",
2502 schema: r#"{
2503 "type": "object",
2504 "properties": {
2505 "scope": {"type": "string", "description": "Tenant scope prefix"},
2506 "from_timestamp": {"type": "string", "description": "Start of comparison window (ISO-8601)"},
2507 "to_timestamp": {"type": "string", "description": "End of comparison window (ISO-8601)"}
2508 },
2509 "required": ["scope", "from_timestamp", "to_timestamp"]
2510 }"#,
2511 annotations: ToolAnnotations {
2512 read_only_hint: Some(true),
2513 destructive_hint: None,
2514 idempotent_hint: Some(true),
2515 open_world_hint: None,
2516 },
2517 },
2518
2519 ToolDef {
2521 name: "memory_get_public",
2522 description: "Get a memory with all <private>...</private> tagged sections removed. Safe for sharing in multi-agent contexts.",
2523 schema: r#"{
2524 "type": "object",
2525 "properties": {
2526 "id": {"type": "integer", "description": "Memory ID"}
2527 },
2528 "required": ["id"]
2529 }"#,
2530 annotations: ToolAnnotations::read_only(),
2531 },
2532 ToolDef {
2533 name: "memory_search_compact",
2534 description: "Token-efficient search returning only id, title (first line, max 80 chars), created_at, and tags. Use memory_expand to get full content for specific IDs.",
2535 schema: r#"{
2536 "type": "object",
2537 "properties": {
2538 "query": {"type": "string", "description": "Search query"},
2539 "limit": {"type": "integer", "description": "Max results (default: 10)"},
2540 "workspace": {"type": "string", "description": "Filter to workspace"}
2541 },
2542 "required": ["query"]
2543 }"#,
2544 annotations: ToolAnnotations::read_only(),
2545 },
2546 ToolDef {
2547 name: "memory_expand",
2548 description: "Fetch full memory content for specific IDs. Used after memory_search_compact to get full content only for memories you need.",
2549 schema: r#"{
2550 "type": "object",
2551 "properties": {
2552 "ids": {"type": "array", "items": {"type": "integer"}, "description": "Memory IDs to expand"}
2553 },
2554 "required": ["ids"]
2555 }"#,
2556 annotations: ToolAnnotations::read_only(),
2557 },
2558 ToolDef {
2559 name: "memory_get_injection_prompt",
2560 description: "Assembles the most relevant memories into a ready-to-inject system prompt block. Uses hybrid search to find relevant memories and formats them as markdown, respecting a token budget.",
2561 schema: r#"{
2562 "type": "object",
2563 "properties": {
2564 "query": {"type": "string", "description": "Search query to find relevant memories"},
2565 "token_budget": {"type": "integer", "description": "Max tokens for output (default: 2000)"},
2566 "workspace": {"type": "string", "description": "Filter to specific workspace"},
2567 "include_types": {"type": "array", "items": {"type": "string"}, "description": "Filter by memory types"}
2568 },
2569 "required": ["query"]
2570 }"#,
2571 annotations: ToolAnnotations::read_only(),
2572 },
2573 ToolDef {
2574 name: "memory_observe_tool_use",
2575 description: "Store a tool observation as an episodic memory for session continuity. Automatically compresses large inputs/outputs.",
2576 schema: r#"{
2577 "type": "object",
2578 "properties": {
2579 "tool_name": {"type": "string", "description": "Name of the tool that was used"},
2580 "tool_input": {"type": "object", "description": "Tool input parameters"},
2581 "tool_output": {"type": "string", "description": "Tool output/result"},
2582 "session_id": {"type": "string", "description": "Session identifier for grouping observations"},
2583 "compress": {"type": "boolean", "description": "Compress to 200-char previews (default: true)"}
2584 },
2585 "required": ["tool_name", "tool_input", "tool_output"]
2586 }"#,
2587 annotations: ToolAnnotations::mutating(),
2588 },
2589 ToolDef {
2591 name: "memory_archive_tool_output",
2592 description: "Archives a tool's full raw output to memory and returns a compressed summary (~500 tokens) for use in the active context. Transforms O(N²) context growth to O(N) by keeping only summaries in the working context while preserving full outputs for on-demand retrieval.",
2593 schema: r#"{
2594 "type": "object",
2595 "properties": {
2596 "tool_name": {"type": "string", "description": "Name of the tool whose output is being archived"},
2597 "raw_output": {"type": "string", "description": "Full raw output to archive"},
2598 "session_id": {"type": "string", "description": "Session identifier for grouping archived outputs (default: 'unknown')"},
2599 "compress_summary": {"type": "boolean", "description": "Whether to generate a compressed summary (default: true)"},
2600 "summary_tokens": {"type": "integer", "description": "Max tokens for the compressed summary (default: 500)"}
2601 },
2602 "required": ["tool_name", "raw_output"]
2603 }"#,
2604 annotations: ToolAnnotations::mutating(),
2605 },
2606 ToolDef {
2607 name: "memory_get_archived_output",
2608 description: "Retrieves the full raw output for an archived tool observation by its archive ID. Use when you need the complete output that was previously compressed for context efficiency.",
2609 schema: r#"{
2610 "type": "object",
2611 "properties": {
2612 "archive_id": {"type": "integer", "description": "Archive ID returned by memory_archive_tool_output"}
2613 },
2614 "required": ["archive_id"]
2615 }"#,
2616 annotations: ToolAnnotations::read_only(),
2617 },
2618 ToolDef {
2619 name: "memory_get_working_memory",
2620 description: "Assembles all compressed tool observations for a session into a token-budgeted working memory block. Includes archive references for retrieving full outputs on demand. This is the core of the Endless Mode context management system.",
2621 schema: r#"{
2622 "type": "object",
2623 "properties": {
2624 "session_id": {"type": "string", "description": "Session identifier to retrieve observations for"},
2625 "token_budget": {"type": "integer", "description": "Max tokens for the working memory block (default: 4000)"},
2626 "include_tool_names": {"type": "array", "items": {"type": "string"}, "description": "Whitelist of tool names to include (default: all)"}
2627 },
2628 "required": ["session_id"]
2629 }"#,
2630 annotations: ToolAnnotations::read_only(),
2631 },
2632];
2633
2634pub fn get_tool_definitions() -> Vec<ToolDefinition> {
2636 TOOL_DEFINITIONS
2637 .iter()
2638 .map(|def| ToolDefinition {
2639 name: def.name.to_string(),
2640 description: def.description.to_string(),
2641 input_schema: serde_json::from_str(def.schema).unwrap_or(json!({})),
2642 annotations: Some(def.annotations.clone()),
2643 })
2644 .collect()
2645}
2646
2647#[cfg(test)]
2648mod tests {
2649 use super::*;
2650
2651 #[test]
2652 fn test_tool_definitions_all_parseable() {
2653 let tools = get_tool_definitions();
2654 assert!(!tools.is_empty(), "TOOL_DEFINITIONS must not be empty");
2655 for tool in &tools {
2656 assert!(!tool.name.is_empty(), "tool name must not be empty");
2657 assert!(
2658 !tool.description.is_empty(),
2659 "tool description must not be empty"
2660 );
2661 assert!(
2662 tool.input_schema.is_object(),
2663 "tool '{}' schema must be a JSON object",
2664 tool.name
2665 );
2666 }
2667 }
2668
2669 #[test]
2670 fn test_read_only_tools_have_annotation() {
2671 let tools = get_tool_definitions();
2672 let read_only_names = ["memory_get", "memory_list", "memory_search", "memory_stats"];
2673 for name in read_only_names {
2674 let tool = tools
2675 .iter()
2676 .find(|t| t.name == name)
2677 .unwrap_or_else(|| panic!("tool '{}' not found", name));
2678 let ann = tool
2679 .annotations
2680 .as_ref()
2681 .expect("annotations must be present");
2682 assert_eq!(
2683 ann.read_only_hint,
2684 Some(true),
2685 "tool '{}' should have readOnlyHint=true",
2686 name
2687 );
2688 }
2689 }
2690
2691 #[test]
2692 fn test_destructive_tools_have_annotation() {
2693 let tools = get_tool_definitions();
2694 let destructive_names = [
2695 "memory_delete",
2696 "memory_cleanup_expired",
2697 "embedding_cache_clear",
2698 ];
2699 for name in destructive_names {
2700 let tool = tools
2701 .iter()
2702 .find(|t| t.name == name)
2703 .unwrap_or_else(|| panic!("tool '{}' not found", name));
2704 let ann = tool
2705 .annotations
2706 .as_ref()
2707 .expect("annotations must be present");
2708 assert_eq!(
2709 ann.destructive_hint,
2710 Some(true),
2711 "tool '{}' should have destructiveHint=true",
2712 name
2713 );
2714 }
2715 }
2716
2717 #[test]
2718 fn test_idempotent_tools_have_annotation() {
2719 let tools = get_tool_definitions();
2720 let idempotent_names = [
2721 "memory_extract_entities",
2722 "memory_rebuild_embeddings",
2723 "memory_rebuild_crossrefs",
2724 "lifecycle_run",
2725 "retention_policy_apply",
2726 ];
2727 for name in idempotent_names {
2728 let tool = tools
2729 .iter()
2730 .find(|t| t.name == name)
2731 .unwrap_or_else(|| panic!("tool '{}' not found", name));
2732 let ann = tool
2733 .annotations
2734 .as_ref()
2735 .expect("annotations must be present");
2736 assert_eq!(
2737 ann.idempotent_hint,
2738 Some(true),
2739 "tool '{}' should have idempotentHint=true",
2740 name
2741 );
2742 }
2743 }
2744
2745 #[test]
2746 fn test_annotations_serialize_with_camel_case_keys() {
2747 let tools = get_tool_definitions();
2748 let memory_get = tools.iter().find(|t| t.name == "memory_get").unwrap();
2749 let json = serde_json::to_string(memory_get).expect("serialization must succeed");
2750 assert!(
2751 json.contains("readOnlyHint"),
2752 "should serialize as readOnlyHint"
2753 );
2754 assert!(
2755 !json.contains("read_only_hint"),
2756 "must not use snake_case key"
2757 );
2758 }
2759
2760 #[test]
2761 fn test_mutating_tool_has_no_hints() {
2762 let tools = get_tool_definitions();
2763 let memory_create = tools.iter().find(|t| t.name == "memory_create").unwrap();
2764 let ann = memory_create
2765 .annotations
2766 .as_ref()
2767 .expect("annotations must be present");
2768 assert!(ann.read_only_hint.is_none());
2769 assert!(ann.destructive_hint.is_none());
2770 assert!(ann.idempotent_hint.is_none());
2771 let json = serde_json::to_string(ann).expect("serialization must succeed");
2773 assert_eq!(json, "{}");
2775 }
2776}