Skip to content

feat: add on-demand memory storage and recall tools#193

Open
kyteinsky wants to merge 3 commits into
mainfrom
feat/tool-called-memory
Open

feat: add on-demand memory storage and recall tools#193
kyteinsky wants to merge 3 commits into
mainfrom
feat/tool-called-memory

Conversation

@kyteinsky

@kyteinsky kyteinsky commented Jun 18, 2026

Copy link
Copy Markdown
Contributor
image image image image image

needs nextcloud/context_chat#247

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI

Signed-off-by: kyteinsky <kyteinsky@gmail.com>
Assisted-by: Github Copilot:qwen-3-6-35b-a3b
Assisted-by: Github Copilot:claude-sonnet-4-6
@kyteinsky kyteinsky requested review from janepie and marcelklehr June 18, 2026 09:29
@kyteinsky

Copy link
Copy Markdown
Contributor Author

do we want specific tests for this feature in the integration tests?

@kyteinsky kyteinsky requested a review from julien-nc June 18, 2026 09:32
Comment thread ex_app/lib/all_tools/memory.py Outdated
Comment thread ex_app/lib/all_tools/memory.py
Comment thread ex_app/lib/all_tools/memory.py Outdated
Comment thread ex_app/lib/all_tools/memory.py Outdated
Comment thread ex_app/lib/all_tools/memory.py
Comment thread ex_app/lib/all_tools/memory.py
Signed-off-by: kyteinsky <kyteinsky@gmail.com>
Signed-off-by: kyteinsky <kyteinsky@gmail.com>
@marcelklehr

Copy link
Copy Markdown
Member

Nice! We can now make the memory tools dependent on the assistant app being installed and it should be ok

Comment thread ex_app/lib/all_tools/memory.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new “Memories” toolset that lets the agent persist, browse, load, delete, and (optionally) semantically search user-scoped memory files stored under the Assistant folder in Nextcloud. It also updates TaskProcessing output validation to support the new Context Chat search output shape.

Changes:

  • Added ex_app/lib/all_tools/memory.py implementing memory storage/recall tools (list/load/store/delete/delete-folder/search).
  • Added DAV folder-creation logic to ensure the Memories base folder and subfolders exist when storing memories.
  • Updated TaskProcessing output-key validation to accept sources outputs.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

File Description
ex_app/lib/all_tools/memory.py Adds new memory management tools + path validation + DAV folder creation + Context Chat-backed semantic search.
ex_app/lib/all_tools/lib/task_processing.py Extends accepted TaskProcessing output keys to include sources for Context Chat search results.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ex_app/lib/all_tools/memory.py
Comment on lines +96 to +98
path_parts = [p for p in decoded.strip('/').split('/') if p]
if len(path_parts) > MAX_MEMORY_FOLDER_DEPTH + 1: # +1 for the filename itself
raise AgentFacingError(f'Memory path exceeds maximum depth of {MAX_MEMORY_FOLDER_DEPTH}')
Comment on lines +145 to +148
base_parts = [p for p in base_memories_path.split('/') if p]
all_parts = base_parts + scoped_folder_parts
for i in range(len(base_parts) + 1, len(all_parts) + 1):
folder_path = '/'.join(all_parts[:i])
Comment on lines +369 to +374
fsnode = await files_handle.by_id(file_id)
filepath = '/' + fsnode.user_path.removeprefix(prefix).rstrip('/')

if fsnode is None:
await log(nc, logging.WARNING, f'Could not fetch file by id: {file_id}')
return {'path': filepath, 'content': ''}
Comment on lines +316 to +317
try:
full_path, _ = __validate_memory_path(path, memories_folder_path, allow_folder_path=True)

if not isinstance(task.output, dict) or all(x not in ["file", "output", "images", "slide_deck"] for x in task.output):
if not isinstance(task.output, dict) or all(x not in ["file", "output", "images", "slide_deck", "sources"] for x in task.output):
raise Exception('"output" key not found in Nextcloud TaskProcessing task result')
Comment on lines +73 to +75
async def __is_context_chat_available(nc: AsyncNextcloudApp, memories_folder_path: str):
tasktypes = (await nc.ocs('GET', '/ocs/v2.php/taskprocessing/tasktypes'))['types'].keys()
return CONTEXT_CHAT_SEARCH_TASK_TYPE in tasktypes
@marcelklehr

Copy link
Copy Markdown
Member

Works nicely. I didn't test the context_chat integration though, because I don't want to set it up 😇

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants