Coverage for astrocyte/integrations/strands.py: 71%
34 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-04 05:24 +0000
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-04 05:24 +0000
1"""Strands Agents (AWS) integration — Astrocyte as agent tools.
3Usage:
4 from astrocyte import Astrocyte
5 from astrocyte.integrations.strands import astrocyte_strands_tools
7 brain = Astrocyte.from_config("astrocyte.yaml")
8 tools = astrocyte_strands_tools(brain, bank_id="user-123")
10 # Register with Strands agent
11 from strands import Agent
12 agent = Agent(model=model, tools=tools)
14Strands Agents uses a tool specification pattern where each tool has:
15- A spec dict (name, description, inputSchema in JSON Schema format)
16- A handler function that receives the tool input
17"""
19from __future__ import annotations
21import json
22from typing import TYPE_CHECKING, Any
24if TYPE_CHECKING:
25 from astrocyte._astrocyte import Astrocyte
27from astrocyte.types import AstrocyteContext
30def astrocyte_strands_tools(
31 brain: Astrocyte,
32 bank_id: str,
33 *,
34 context: AstrocyteContext | None = None,
35 include_reflect: bool = True,
36 include_forget: bool = False,
37) -> list[dict[str, Any]]:
38 """Create Strands-compatible tool definitions backed by Astrocyte.
40 Returns a list of dicts, each with 'spec' (JSON Schema) and 'handler' (async callable).
41 Strands Agents registers tools with this pattern.
42 """
43 tools: list[dict[str, Any]] = []
45 # ── memory_retain ──
47 async def retain_handler(tool_input: dict[str, Any]) -> str:
48 content = tool_input["content"]
49 tags = tool_input.get("tags")
50 result = await brain.retain(content, bank_id=bank_id, tags=tags, context=context)
51 return json.dumps({"stored": result.stored, "memory_id": result.memory_id})
53 tools.append(
54 {
55 "spec": {
56 "name": "memory_retain",
57 "description": "Store content into long-term memory for future recall.",
58 "inputSchema": {
59 "json": {
60 "type": "object",
61 "properties": {
62 "content": {"type": "string", "description": "The text to memorize."},
63 "tags": {
64 "type": "array",
65 "items": {"type": "string"},
66 "description": "Optional tags for filtering.",
67 },
68 },
69 "required": ["content"],
70 }
71 },
72 },
73 "handler": retain_handler,
74 }
75 )
77 # ── memory_recall ──
79 async def recall_handler(tool_input: dict[str, Any]) -> str:
80 query = tool_input["query"]
81 max_results = tool_input.get("max_results", 5)
82 result = await brain.recall(query, bank_id=bank_id, max_results=max_results, context=context)
83 hits = [{"text": h.text, "score": round(h.score, 4)} for h in result.hits]
84 return json.dumps({"hits": hits, "total": result.total_available})
86 tools.append(
87 {
88 "spec": {
89 "name": "memory_recall",
90 "description": "Search long-term memory for information relevant to a query.",
91 "inputSchema": {
92 "json": {
93 "type": "object",
94 "properties": {
95 "query": {"type": "string", "description": "Natural language search query."},
96 "max_results": {"type": "integer", "description": "Maximum results.", "default": 5},
97 },
98 "required": ["query"],
99 }
100 },
101 },
102 "handler": recall_handler,
103 }
104 )
106 # ── memory_reflect ──
108 if include_reflect:
110 async def reflect_handler(tool_input: dict[str, Any]) -> str:
111 query = tool_input["query"]
112 result = await brain.reflect(query, bank_id=bank_id, context=context)
113 return json.dumps({"answer": result.answer})
115 tools.append(
116 {
117 "spec": {
118 "name": "memory_reflect",
119 "description": "Synthesize a comprehensive answer from long-term memory.",
120 "inputSchema": {
121 "json": {
122 "type": "object",
123 "properties": {
124 "query": {"type": "string", "description": "The question to answer."},
125 },
126 "required": ["query"],
127 }
128 },
129 },
130 "handler": reflect_handler,
131 }
132 )
134 # ── memory_forget ──
136 if include_forget:
138 async def forget_handler(tool_input: dict[str, Any]) -> str:
139 memory_ids = tool_input["memory_ids"]
140 if isinstance(memory_ids, str):
141 memory_ids = [mid.strip() for mid in memory_ids.split(",")]
142 result = await brain.forget(bank_id, memory_ids=memory_ids, context=context)
143 return json.dumps({"deleted_count": result.deleted_count})
145 tools.append(
146 {
147 "spec": {
148 "name": "memory_forget",
149 "description": "Remove specific memories by their IDs.",
150 "inputSchema": {
151 "json": {
152 "type": "object",
153 "properties": {
154 "memory_ids": {
155 "type": "array",
156 "items": {"type": "string"},
157 "description": "IDs of memories to delete.",
158 },
159 },
160 "required": ["memory_ids"],
161 }
162 },
163 },
164 "handler": forget_handler,
165 }
166 )
168 return tools