Files
alfred/alfred/agent/tools/workflow.py
T
francwa 23a9dd7990 refactor(memory): rename workflow.target -> params, type -> name
The Workflow STM component stored an active workflow as
{type, target, stage, started_at}. Now that start_workflow takes a
workflow_name and a params dict, those keys match what they actually
hold:

  type   -> name    (the YAML workflow name, e.g. media.organize_media)
  target -> params  (the dict passed to start_workflow)

ShortTermMemory.start_workflow parameters renamed accordingly. All
consumers (prompt builder workflow scope + STM context, start/end
workflow tools) updated.
2026-05-14 21:11:23 +02:00

87 lines
2.5 KiB
Python

"""Workflow scoping tools — start_workflow / end_workflow meta-tools.
These tools let the agent enter and leave a workflow scope. While a
workflow is active, the PromptBuilder narrows the visible tool catalog
to the noyau + the workflow's declared tools, so the LLM doesn't have
to reason over the full set.
"""
import logging
from typing import Any
from alfred.infrastructure.persistence import get_memory
from ..workflows import WorkflowLoader
logger = logging.getLogger(__name__)
_loader_cache: list[WorkflowLoader] = []
def _get_loader() -> WorkflowLoader:
"""Lazily build the module-level WorkflowLoader."""
if not _loader_cache:
_loader_cache.append(WorkflowLoader())
return _loader_cache[0]
def start_workflow(workflow_name: str, params: dict) -> dict[str, Any]:
"""See specs/start_workflow.yaml for full description."""
loader = _get_loader()
workflow = loader.get(workflow_name)
if workflow is None:
return {
"status": "error",
"error": "unknown_workflow",
"message": f"Workflow '{workflow_name}' not found",
"available_workflows": loader.names(),
}
memory = get_memory()
current = memory.stm.workflow.current
if current is not None:
return {
"status": "error",
"error": "workflow_already_active",
"message": (
f"Workflow '{current.get('name')}' is already active. "
"Call end_workflow before starting a new one."
),
"active_workflow": current.get("name"),
}
memory.stm.start_workflow(workflow_name, params or {})
memory.save()
logger.info(f"start_workflow: '{workflow_name}' with params={params}")
return {
"status": "ok",
"workflow": workflow_name,
"description": workflow.get("description", ""),
"steps": workflow.get("steps", []),
"tools": workflow.get("tools", []),
}
def end_workflow(reason: str) -> dict[str, Any]:
"""See specs/end_workflow.yaml for full description."""
memory = get_memory()
current = memory.stm.workflow.current
if current is None:
return {
"status": "error",
"error": "no_active_workflow",
"message": "No workflow is currently active.",
}
workflow_name = current.get("name")
memory.stm.end_workflow()
memory.save()
logger.info(f"end_workflow: '{workflow_name}' reason={reason!r}")
return {
"status": "ok",
"workflow": workflow_name,
"reason": reason,
}