docugraph 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docugraph/__init__.py +24 -0
- docugraph/_version.py +28 -0
- docugraph/agents/__init__.py +27 -0
- docugraph/agents/coding_agent.py +532 -0
- docugraph/agents/tools/__init__.py +62 -0
- docugraph/agents/tools/graph_query.py +203 -0
- docugraph/agents/tools/memory_ops.py +305 -0
- docugraph/agents/tools/search_code.py +305 -0
- docugraph/agents/tools/search_docs.py +148 -0
- docugraph/core/__init__.py +34 -0
- docugraph/core/config.py +183 -0
- docugraph/core/embeddings.py +394 -0
- docugraph/core/llm.py +892 -0
- docugraph/core/models.py +145 -0
- docugraph/ingestion/__init__.py +64 -0
- docugraph/ingestion/api_docs.py +646 -0
- docugraph/ingestion/chunker.py +382 -0
- docugraph/ingestion/crawler.py +305 -0
- docugraph/ingestion/git_indexer.py +556 -0
- docugraph/ingestion/local_files.py +516 -0
- docugraph/interfaces/__init__.py +1 -0
- docugraph/interfaces/cli.py +983 -0
- docugraph/interfaces/mcp_server.py +918 -0
- docugraph/retrieval/__init__.py +54 -0
- docugraph/retrieval/context_builder.py +522 -0
- docugraph/retrieval/hybrid_search.py +534 -0
- docugraph/retrieval/reranker.py +532 -0
- docugraph/storage/__init__.py +14 -0
- docugraph/storage/graph_store.py +602 -0
- docugraph/storage/memory_store.py +529 -0
- docugraph/storage/vector_store.py +367 -0
- docugraph-0.1.0.dist-info/METADATA +354 -0
- docugraph-0.1.0.dist-info/RECORD +37 -0
- docugraph-0.1.0.dist-info/WHEEL +4 -0
- docugraph-0.1.0.dist-info/entry_points.txt +3 -0
- docugraph-0.1.0.dist-info/licenses/LICENSE +201 -0
- docugraph-0.1.0.dist-info/licenses/NOTICE +10 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"""Knowledge graph query tool for the coding agent.
|
|
2
|
+
|
|
3
|
+
Provides access to the knowledge graph for entity and relationship queries.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def graph_query(
|
|
13
|
+
query: str,
|
|
14
|
+
num_results: int = 10,
|
|
15
|
+
group_id: str | None = None,
|
|
16
|
+
_context: Any = None,
|
|
17
|
+
**_kwargs: Any,
|
|
18
|
+
) -> list[dict[str, Any]]:
|
|
19
|
+
"""Query the knowledge graph for facts and relationships.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
query: Natural language query
|
|
23
|
+
num_results: Maximum number of results
|
|
24
|
+
group_id: Optional group ID filter
|
|
25
|
+
_context: Agent execution context (injected)
|
|
26
|
+
**kwargs: Additional arguments
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
List of facts from the knowledge graph
|
|
30
|
+
"""
|
|
31
|
+
from docugraph.storage.graph_store import GraphStore
|
|
32
|
+
|
|
33
|
+
store = GraphStore()
|
|
34
|
+
group_ids = [group_id] if group_id else None
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
results = await store.search(
|
|
38
|
+
query=query,
|
|
39
|
+
group_ids=group_ids,
|
|
40
|
+
num_results=num_results,
|
|
41
|
+
)
|
|
42
|
+
return results
|
|
43
|
+
finally:
|
|
44
|
+
await store.close()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
async def graph_add_content(
|
|
48
|
+
content: str,
|
|
49
|
+
name: str | None = None,
|
|
50
|
+
group_id: str = "default",
|
|
51
|
+
source_type: str = "text",
|
|
52
|
+
_context: Any = None,
|
|
53
|
+
**_kwargs: Any,
|
|
54
|
+
) -> dict[str, Any]:
|
|
55
|
+
"""Add content to the knowledge graph.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
content: Content to extract entities from
|
|
59
|
+
name: Episode name (optional)
|
|
60
|
+
group_id: Group ID for scoping
|
|
61
|
+
source_type: Content type (text, json)
|
|
62
|
+
_context: Agent execution context (injected)
|
|
63
|
+
**kwargs: Additional arguments
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Information about extracted entities and relationships
|
|
67
|
+
"""
|
|
68
|
+
from docugraph.storage.graph_store import GraphStore
|
|
69
|
+
|
|
70
|
+
store = GraphStore()
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
episode_name = name or f"episode_{hash(content) % 10000}"
|
|
74
|
+
result = await store.add_episode(
|
|
75
|
+
name=episode_name,
|
|
76
|
+
content=content,
|
|
77
|
+
source_type=source_type,
|
|
78
|
+
group_id=group_id,
|
|
79
|
+
)
|
|
80
|
+
return result
|
|
81
|
+
finally:
|
|
82
|
+
await store.close()
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
async def find_related_entities(
|
|
86
|
+
entity_name: str,
|
|
87
|
+
relationship_type: str | None = None,
|
|
88
|
+
max_depth: int = 2,
|
|
89
|
+
_context: Any = None,
|
|
90
|
+
**_kwargs: Any,
|
|
91
|
+
) -> list[dict[str, Any]]:
|
|
92
|
+
"""Find entities related to a given entity.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
entity_name: Name of the entity to start from
|
|
96
|
+
relationship_type: Filter by relationship type (USES, DEPENDS_ON, etc.)
|
|
97
|
+
max_depth: How deep to look — widens the result pool per hop
|
|
98
|
+
_context: Agent execution context (injected)
|
|
99
|
+
**kwargs: Additional arguments
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
List of related entities with relationship information
|
|
103
|
+
"""
|
|
104
|
+
# Query for the entity and its relationships
|
|
105
|
+
query = f"What is related to {entity_name}?"
|
|
106
|
+
if relationship_type:
|
|
107
|
+
query = f"What does {entity_name} {relationship_type.lower().replace('_', ' ')}?"
|
|
108
|
+
|
|
109
|
+
# Deeper searches pull a proportionally wider pool of graph facts.
|
|
110
|
+
results = await graph_query(
|
|
111
|
+
query=query,
|
|
112
|
+
num_results=10 * max(1, max_depth),
|
|
113
|
+
_context=_context,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Filter results that mention the entity
|
|
117
|
+
related = []
|
|
118
|
+
entity_lower = entity_name.lower()
|
|
119
|
+
|
|
120
|
+
for r in results:
|
|
121
|
+
fact = r.get("fact", "").lower()
|
|
122
|
+
if entity_lower in fact:
|
|
123
|
+
related.append(r)
|
|
124
|
+
|
|
125
|
+
return related
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
async def get_entity_context(
|
|
129
|
+
entity_name: str,
|
|
130
|
+
include_relationships: bool = True,
|
|
131
|
+
_context: Any = None,
|
|
132
|
+
**_kwargs: Any,
|
|
133
|
+
) -> dict[str, Any]:
|
|
134
|
+
"""Get comprehensive context about an entity.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
entity_name: Name of the entity
|
|
138
|
+
include_relationships: Include relationship information
|
|
139
|
+
_context: Agent execution context (injected)
|
|
140
|
+
**kwargs: Additional arguments
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Entity context including facts, relationships, and documentation
|
|
144
|
+
"""
|
|
145
|
+
# Query for entity facts
|
|
146
|
+
entity_facts = await graph_query(
|
|
147
|
+
query=f"What is {entity_name}?",
|
|
148
|
+
num_results=10,
|
|
149
|
+
_context=_context,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
context = {
|
|
153
|
+
"entity": entity_name,
|
|
154
|
+
"facts": entity_facts,
|
|
155
|
+
"relationships": [],
|
|
156
|
+
"documentation": [],
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if include_relationships:
|
|
160
|
+
# Get relationships
|
|
161
|
+
relationships = await find_related_entities(
|
|
162
|
+
entity_name=entity_name,
|
|
163
|
+
_context=_context,
|
|
164
|
+
)
|
|
165
|
+
context["relationships"] = relationships
|
|
166
|
+
|
|
167
|
+
# Also search documentation. This function is async, so it awaits the
|
|
168
|
+
# async entry point rather than driving a loop of its own.
|
|
169
|
+
from docugraph.agents.tools.search_docs import search_docs_async
|
|
170
|
+
|
|
171
|
+
doc_results = await search_docs_async(
|
|
172
|
+
query=entity_name,
|
|
173
|
+
top_k=3,
|
|
174
|
+
_context=_context,
|
|
175
|
+
)
|
|
176
|
+
context["documentation"] = doc_results
|
|
177
|
+
|
|
178
|
+
return context
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def query_entities_sync(
|
|
182
|
+
query: str,
|
|
183
|
+
num_results: int = 10,
|
|
184
|
+
group_id: str | None = None,
|
|
185
|
+
_context: Any = None,
|
|
186
|
+
**_kwargs: Any,
|
|
187
|
+
) -> list[dict[str, Any]]:
|
|
188
|
+
"""Synchronous wrapper for graph_query, for callers with no event loop.
|
|
189
|
+
|
|
190
|
+
Async callers await ``graph_query`` itself -- this drives a fresh loop and
|
|
191
|
+
raises if one is already running, which is the signal to await instead.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
query: Natural language query
|
|
195
|
+
num_results: Maximum number of results
|
|
196
|
+
group_id: Optional group ID filter
|
|
197
|
+
_context: Agent execution context (injected)
|
|
198
|
+
**kwargs: Additional arguments
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
List of facts from the knowledge graph
|
|
202
|
+
"""
|
|
203
|
+
return asyncio.run(graph_query(query, num_results, group_id, _context))
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"""Memory operations tool for the coding agent.
|
|
2
|
+
|
|
3
|
+
Provides session memory for storing and retrieving context, decisions,
|
|
4
|
+
and other information scoped by repository and branch.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from datetime import UTC, datetime
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _scope_or_defaults(
|
|
14
|
+
repository: str | None,
|
|
15
|
+
branch: str | None,
|
|
16
|
+
_context: Any,
|
|
17
|
+
) -> tuple[str, str]:
|
|
18
|
+
"""Resolve repository/branch scope: explicit arg, then context, then defaults."""
|
|
19
|
+
repo = repository or (getattr(_context, "repository", "default") if _context else "default")
|
|
20
|
+
br = branch or (getattr(_context, "branch", "main") if _context else "main")
|
|
21
|
+
return str(repo), str(br)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def memory_store(
|
|
25
|
+
key: str,
|
|
26
|
+
value: Any,
|
|
27
|
+
repository: str | None = None,
|
|
28
|
+
branch: str | None = None,
|
|
29
|
+
_context: Any = None,
|
|
30
|
+
**_kwargs: Any,
|
|
31
|
+
) -> dict[str, Any]:
|
|
32
|
+
"""Store a value in agent memory.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
key: Key to store the value under
|
|
36
|
+
value: Value to store (can be any JSON-serializable type)
|
|
37
|
+
repository: Repository scope (defaults to context or 'default')
|
|
38
|
+
branch: Branch scope (defaults to context or 'main')
|
|
39
|
+
_context: Agent execution context (injected)
|
|
40
|
+
**kwargs: Additional arguments
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Confirmation with stored entry details
|
|
44
|
+
"""
|
|
45
|
+
from docugraph.storage.memory_store import MemoryStore
|
|
46
|
+
|
|
47
|
+
# Get scope from context or defaults
|
|
48
|
+
repository, branch = _scope_or_defaults(repository, branch, _context)
|
|
49
|
+
|
|
50
|
+
store = MemoryStore()
|
|
51
|
+
entry = store.set(
|
|
52
|
+
key=key,
|
|
53
|
+
value=value,
|
|
54
|
+
repository=repository,
|
|
55
|
+
branch=branch,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
"key": entry.key,
|
|
60
|
+
"value": entry.value,
|
|
61
|
+
"repository": entry.repository,
|
|
62
|
+
"branch": entry.branch,
|
|
63
|
+
"created_at": entry.created_at.isoformat() if entry.created_at else None,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def memory_recall(
|
|
68
|
+
key: str,
|
|
69
|
+
repository: str | None = None,
|
|
70
|
+
branch: str | None = None,
|
|
71
|
+
default: Any = None,
|
|
72
|
+
_context: Any = None,
|
|
73
|
+
**_kwargs: Any,
|
|
74
|
+
) -> Any:
|
|
75
|
+
"""Retrieve a value from agent memory.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
key: Key to retrieve (or '*' for all keys)
|
|
79
|
+
repository: Repository scope (defaults to context or 'default')
|
|
80
|
+
branch: Branch scope (defaults to context or 'main')
|
|
81
|
+
default: Default value if key not found
|
|
82
|
+
_context: Agent execution context (injected)
|
|
83
|
+
**kwargs: Additional arguments
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Stored value or default if not found
|
|
87
|
+
"""
|
|
88
|
+
from docugraph.storage.memory_store import MemoryStore
|
|
89
|
+
|
|
90
|
+
# Get scope from context or defaults
|
|
91
|
+
repository, branch = _scope_or_defaults(repository, branch, _context)
|
|
92
|
+
|
|
93
|
+
store = MemoryStore()
|
|
94
|
+
|
|
95
|
+
# List all keys
|
|
96
|
+
if key == "*":
|
|
97
|
+
keys = store.list_keys(repository=repository, branch=branch)
|
|
98
|
+
return {
|
|
99
|
+
"keys": keys,
|
|
100
|
+
"repository": repository,
|
|
101
|
+
"branch": branch,
|
|
102
|
+
"total": len(keys),
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# Get specific key
|
|
106
|
+
value = store.get(key, repository=repository, branch=branch)
|
|
107
|
+
if value is None:
|
|
108
|
+
return default
|
|
109
|
+
|
|
110
|
+
return value
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def memory_delete(
|
|
114
|
+
key: str,
|
|
115
|
+
repository: str | None = None,
|
|
116
|
+
branch: str | None = None,
|
|
117
|
+
_context: Any = None,
|
|
118
|
+
**_kwargs: Any,
|
|
119
|
+
) -> dict[str, Any]:
|
|
120
|
+
"""Delete a value from agent memory.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
key: Key to delete
|
|
124
|
+
repository: Repository scope
|
|
125
|
+
branch: Branch scope
|
|
126
|
+
_context: Agent execution context (injected)
|
|
127
|
+
**kwargs: Additional arguments
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Confirmation with deletion status
|
|
131
|
+
"""
|
|
132
|
+
from docugraph.storage.memory_store import MemoryStore
|
|
133
|
+
|
|
134
|
+
# Get scope from context or defaults
|
|
135
|
+
repository, branch = _scope_or_defaults(repository, branch, _context)
|
|
136
|
+
|
|
137
|
+
store = MemoryStore()
|
|
138
|
+
deleted = store.delete(key, repository=repository, branch=branch)
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
"key": key,
|
|
142
|
+
"deleted": deleted,
|
|
143
|
+
"repository": repository,
|
|
144
|
+
"branch": branch,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def memory_search(
|
|
149
|
+
pattern: str,
|
|
150
|
+
repository: str | None = None,
|
|
151
|
+
branch: str | None = None,
|
|
152
|
+
_context: Any = None,
|
|
153
|
+
**_kwargs: Any,
|
|
154
|
+
) -> list[dict[str, Any]]:
|
|
155
|
+
"""Search memory keys by pattern.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
pattern: Pattern to search for (supports % wildcard)
|
|
159
|
+
repository: Repository scope
|
|
160
|
+
branch: Branch scope
|
|
161
|
+
_context: Agent execution context (injected)
|
|
162
|
+
**kwargs: Additional arguments
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
List of matching entries with keys and values
|
|
166
|
+
"""
|
|
167
|
+
from docugraph.storage.memory_store import MemoryStore
|
|
168
|
+
|
|
169
|
+
# Get scope from context or defaults
|
|
170
|
+
repository, branch = _scope_or_defaults(repository, branch, _context)
|
|
171
|
+
|
|
172
|
+
store = MemoryStore()
|
|
173
|
+
keys = store.list_keys(repository=repository, branch=branch)
|
|
174
|
+
|
|
175
|
+
# Filter by pattern
|
|
176
|
+
import fnmatch
|
|
177
|
+
|
|
178
|
+
# Convert SQL-style wildcard to glob-style
|
|
179
|
+
glob_pattern = pattern.replace("%", "*")
|
|
180
|
+
matching_keys = fnmatch.filter(keys, glob_pattern)
|
|
181
|
+
|
|
182
|
+
# Get values for matching keys
|
|
183
|
+
results = []
|
|
184
|
+
for key in matching_keys:
|
|
185
|
+
value = store.get(key, repository=repository, branch=branch)
|
|
186
|
+
results.append(
|
|
187
|
+
{
|
|
188
|
+
"key": key,
|
|
189
|
+
"value": value,
|
|
190
|
+
"repository": repository,
|
|
191
|
+
"branch": branch,
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
return results
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def store_decision(
|
|
199
|
+
decision: str,
|
|
200
|
+
reasoning: str,
|
|
201
|
+
context: dict[str, Any] | None = None,
|
|
202
|
+
_context: Any = None,
|
|
203
|
+
**_kwargs: Any,
|
|
204
|
+
) -> dict[str, Any]:
|
|
205
|
+
"""Store a decision with reasoning for future reference.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
decision: The decision made
|
|
209
|
+
reasoning: Why this decision was made
|
|
210
|
+
context: Additional context
|
|
211
|
+
_context: Agent execution context (injected)
|
|
212
|
+
**kwargs: Additional arguments
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
Stored decision entry
|
|
216
|
+
"""
|
|
217
|
+
# Generate a unique key for the decision
|
|
218
|
+
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
|
|
219
|
+
key = f"decision_{timestamp}"
|
|
220
|
+
|
|
221
|
+
value = {
|
|
222
|
+
"decision": decision,
|
|
223
|
+
"reasoning": reasoning,
|
|
224
|
+
"context": context or {},
|
|
225
|
+
"timestamp": datetime.now(UTC).isoformat(),
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return memory_store(key=key, value=value, _context=_context)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def recall_decisions(
|
|
232
|
+
limit: int = 10,
|
|
233
|
+
_context: Any = None,
|
|
234
|
+
**_kwargs: Any,
|
|
235
|
+
) -> list[dict[str, Any]]:
|
|
236
|
+
"""Recall recent decisions.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
limit: Maximum number of decisions to return
|
|
240
|
+
_context: Agent execution context (injected)
|
|
241
|
+
**kwargs: Additional arguments
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
List of recent decisions
|
|
245
|
+
"""
|
|
246
|
+
results = memory_search(pattern="decision_%", _context=_context)
|
|
247
|
+
|
|
248
|
+
# Sort by key (which includes timestamp) and return most recent
|
|
249
|
+
results.sort(key=lambda x: x["key"], reverse=True)
|
|
250
|
+
|
|
251
|
+
decisions = []
|
|
252
|
+
for r in results[:limit]:
|
|
253
|
+
value = r.get("value", {})
|
|
254
|
+
if isinstance(value, dict):
|
|
255
|
+
decisions.append(
|
|
256
|
+
{
|
|
257
|
+
"key": r["key"],
|
|
258
|
+
"decision": value.get("decision"),
|
|
259
|
+
"reasoning": value.get("reasoning"),
|
|
260
|
+
"timestamp": value.get("timestamp"),
|
|
261
|
+
}
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
return decisions
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def store_context(
|
|
268
|
+
context_type: str,
|
|
269
|
+
data: dict[str, Any],
|
|
270
|
+
_context: Any = None,
|
|
271
|
+
**_kwargs: Any,
|
|
272
|
+
) -> dict[str, Any]:
|
|
273
|
+
"""Store contextual information.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
context_type: Type of context (e.g., 'architecture', 'dependencies')
|
|
277
|
+
data: Context data
|
|
278
|
+
_context: Agent execution context (injected)
|
|
279
|
+
**kwargs: Additional arguments
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
Stored context entry
|
|
283
|
+
"""
|
|
284
|
+
key = f"context_{context_type}"
|
|
285
|
+
return memory_store(key=key, value=data, _context=_context)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def recall_context(
|
|
289
|
+
context_type: str,
|
|
290
|
+
_context: Any = None,
|
|
291
|
+
**_kwargs: Any,
|
|
292
|
+
) -> dict[str, Any] | None:
|
|
293
|
+
"""Recall contextual information.
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
context_type: Type of context to recall
|
|
297
|
+
_context: Agent execution context (injected)
|
|
298
|
+
**kwargs: Additional arguments
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
Context data or None if not found
|
|
302
|
+
"""
|
|
303
|
+
key = f"context_{context_type}"
|
|
304
|
+
result: dict[str, Any] | None = memory_recall(key=key, default=None, _context=_context)
|
|
305
|
+
return result
|