Skip to content

Commit d3ee9a1

Browse files
committed
feat(workflows-mcp): add get_all() to ExecutionMemory and flush_memory_on_complete to WorkflowSchema
1 parent 7c90e9a commit d3ee9a1

3 files changed

Lines changed: 35 additions & 0 deletions

File tree

src/workflows_mcp/engine/execution_memory.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,16 @@ async def set(self, key: str, value: str, scope: str = "global") -> None:
9999
)
100100
await asyncio.to_thread(self._conn.commit)
101101

102+
async def get_all(self, scope: str = "global") -> dict[str, str]:
103+
"""Retrieve all key-value pairs for a given scope."""
104+
assert self._conn is not None, "ExecutionMemory not initialized"
105+
cursor = await asyncio.to_thread(
106+
self._conn.execute,
107+
"SELECT key, value FROM execution_context WHERE scope = ? ORDER BY key",
108+
(scope,),
109+
)
110+
return {row[0]: row[1] for row in cursor.fetchall()}
111+
102112
# ------------------------------------------------------------------
103113
# Conversation Turns
104114
# ------------------------------------------------------------------

src/workflows_mcp/engine/schema.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,10 @@ class WorkflowSchema(BaseModel):
578578
version: str = Field(default="1.0", pattern=r"^\d+\.\d+(\.\d+)?$")
579579
author: str | None = Field(default=None)
580580
tags: list[str] = Field(default_factory=list)
581+
flush_memory_on_complete: bool = Field(
582+
default=False,
583+
description="Flush global-scoped memory entries to durable knowledge on completion",
584+
)
581585

582586
# Workflow structure
583587
inputs: dict[str, WorkflowInputDeclaration] = Field(

tests/test_execution_memory.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,27 @@ async def test_scoped_key_missing(self, memory: ExecutionMemory) -> None:
5353
await memory.set("key", "val", scope="block:a")
5454
assert await memory.get("key", scope="block:b") is None
5555

56+
@pytest.mark.asyncio
57+
async def test_get_all_returns_global_entries(self, memory: ExecutionMemory) -> None:
58+
await memory.set("alpha", "1")
59+
await memory.set("beta", "2")
60+
result = await memory.get_all("global")
61+
assert result == {"alpha": "1", "beta": "2"}
62+
63+
@pytest.mark.asyncio
64+
async def test_get_all_scoped_isolation(self, memory: ExecutionMemory) -> None:
65+
"""get_all('global') should not include block-scoped entries."""
66+
await memory.set("shared", "global_val", scope="global")
67+
await memory.set("local", "block_val", scope="block:step_1")
68+
result = await memory.get_all("global")
69+
assert result == {"shared": "global_val"}
70+
assert "local" not in result
71+
72+
@pytest.mark.asyncio
73+
async def test_get_all_empty(self, memory: ExecutionMemory) -> None:
74+
result = await memory.get_all("global")
75+
assert result == {}
76+
5677

5778
# -----------------------------------------------------------------------
5879
# Conversation Turns

0 commit comments

Comments
 (0)