23a9dd7990
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.
87 lines
2.5 KiB
Python
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,
|
|
}
|