refactor(agents): group tool-outcome receipts into multi_agent_chat/shared/receipts/

receipt.py (Receipt model + make_receipt) and receipt_command.py
(with_receipt Command helper) are a tight pair used only by MAC subagent
tools, the graph state, and the kb_persistence middleware -- no external
code imports them (the streaming tool_end handler only references them in a
docstring). Move both into a dedicated receipts/ package
(receipts/receipt.py + receipts/command.py) and repoint importers.

No behavior change; import-all + receipt/deliverable unit tests stay green.
This commit is contained in:
CREDO23 2026-06-05 10:56:37 +02:00
parent 1d2519730e
commit 714c5ffea9
13 changed files with 19 additions and 19 deletions

View file

@ -24,7 +24,7 @@ from typing import Any
from langchain_core.messages import ToolMessage
from langgraph.types import Command
from app.agents.shared.receipt import Receipt
from app.agents.multi_agent_chat.shared.receipts.receipt import Receipt
def _content_to_text(payload: dict[str, Any] | str) -> str:

View file

@ -30,6 +30,7 @@ from typing import Annotated, Any, NotRequired
from deepagents.middleware.filesystem import FilesystemState
from typing_extensions import TypedDict
from app.agents.multi_agent_chat.shared.receipts.receipt import Receipt
from app.agents.multi_agent_chat.shared.state.reducers import (
_add_unique_reducer,
_dict_merge_with_tombstones_reducer,
@ -37,7 +38,6 @@ from app.agents.multi_agent_chat.shared.state.reducers import (
_list_append_reducer,
_replace_reducer,
)
from app.agents.shared.receipt import Receipt
class PendingMove(TypedDict, total=False):
@ -190,7 +190,7 @@ class SurfSenseFilesystemState(FilesystemState):
Each mutating tool (deliverables, every connector, KB writes via the
persistence middleware) wraps its native return into a
:class:`~app.agents.shared.receipt.Receipt`
:class:`~app.agents.multi_agent_chat.shared.receipts.receipt.Receipt`
and returns it under the ``"receipt"`` key alongside its existing
payload. The subagent's tool-call middleware folds the receipt into
this list, and ``_return_command_with_state_update`` in

View file

@ -11,8 +11,8 @@ from litellm import aimage_generation
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.agents.shared.receipt import make_receipt
from app.agents.shared.receipt_command import with_receipt
from app.agents.multi_agent_chat.shared.receipts.command import with_receipt
from app.agents.multi_agent_chat.shared.receipts.receipt import make_receipt
from app.config import config
from app.db import (
ImageGeneration,

View file

@ -16,9 +16,9 @@ from langchain_core.tools import tool
from langgraph.types import Command
from sqlalchemy.ext.asyncio import AsyncSession
from app.agents.multi_agent_chat.shared.receipts.command import with_receipt
from app.agents.multi_agent_chat.shared.receipts.receipt import make_receipt
from app.agents.shared.deliverable_wait import wait_for_deliverable
from app.agents.shared.receipt import make_receipt
from app.agents.shared.receipt_command import with_receipt
from app.db import Podcast, PodcastStatus, shielded_async_session
logger = logging.getLogger(__name__)

View file

@ -12,8 +12,8 @@ from langchain_core.messages import HumanMessage
from langchain_core.tools import tool
from langgraph.types import Command
from app.agents.shared.receipt import make_receipt
from app.agents.shared.receipt_command import with_receipt
from app.agents.multi_agent_chat.shared.receipts.command import with_receipt
from app.agents.multi_agent_chat.shared.receipts.receipt import make_receipt
from app.db import Report, shielded_async_session
from app.services.connector_service import ConnectorService
from app.services.llm_service import get_document_summary_llm

View file

@ -14,8 +14,8 @@ from langchain_core.messages import HumanMessage
from langchain_core.tools import tool
from langgraph.types import Command
from app.agents.shared.receipt import make_receipt
from app.agents.shared.receipt_command import with_receipt
from app.agents.multi_agent_chat.shared.receipts.command import with_receipt
from app.agents.multi_agent_chat.shared.receipts.receipt import make_receipt
from app.db import Report, shielded_async_session
from app.services.llm_service import get_document_summary_llm

View file

@ -17,9 +17,9 @@ from langchain_core.tools import tool
from langgraph.types import Command
from sqlalchemy.ext.asyncio import AsyncSession
from app.agents.multi_agent_chat.shared.receipts.command import with_receipt
from app.agents.multi_agent_chat.shared.receipts.receipt import make_receipt
from app.agents.shared.deliverable_wait import wait_for_deliverable
from app.agents.shared.receipt import make_receipt
from app.agents.shared.receipt_command import with_receipt
from app.db import VideoPresentation, VideoPresentationStatus, shielded_async_session
logger = logging.getLogger(__name__)

View file

@ -10,11 +10,11 @@ from langchain_core.tools import tool
from langgraph.types import Command
from sqlalchemy.ext.asyncio import AsyncSession
from app.agents.multi_agent_chat.shared.receipts.command import with_receipt
from app.agents.multi_agent_chat.shared.receipts.receipt import make_receipt
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.self_gated import (
request_approval,
)
from app.agents.shared.receipt import make_receipt
from app.agents.shared.receipt_command import with_receipt
from app.services.gmail import GmailToolMetadataService
logger = logging.getLogger(__name__)

View file

@ -6,11 +6,11 @@ from langchain_core.tools import tool
from langgraph.types import Command
from sqlalchemy.ext.asyncio import AsyncSession
from app.agents.multi_agent_chat.shared.receipts.command import with_receipt
from app.agents.multi_agent_chat.shared.receipts.receipt import make_receipt
from app.agents.multi_agent_chat.subagents.shared.hitl.approvals.self_gated import (
request_approval,
)
from app.agents.shared.receipt import make_receipt
from app.agents.shared.receipt_command import with_receipt
from app.connectors.notion_history import NotionAPIError, NotionHistoryConnector
from app.services.notion.tool_metadata_service import NotionToolMetadataService

View file

@ -45,6 +45,7 @@ from sqlalchemy import delete, select, update
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from app.agents.multi_agent_chat.shared.receipts.receipt import Receipt, make_receipt
from app.agents.multi_agent_chat.shared.state.filesystem_state import (
SurfSenseFilesystemState,
)
@ -57,7 +58,6 @@ from app.agents.shared.path_resolver import (
safe_folder_segment,
virtual_path_to_doc,
)
from app.agents.shared.receipt import Receipt, make_receipt
from app.db import (
AgentActionLog,
Chunk,

View file

@ -26,7 +26,7 @@ def _unwrap_command_output(raw_output: Any) -> Any:
"""Replace a ``Command`` from a tool return with its inner ``ToolMessage``.
Tools that participate in receipt-style state writes (see
``app.agents.shared.receipt_command.with_receipt``) return a
``app.agents.multi_agent_chat.shared.receipts.command.with_receipt``) return a
``Command(update={"messages": [ToolMessage(...)], "receipts": [...]})``.
LangChain's ``on_tool_end`` event surfaces that ``Command`` verbatim as
``data.output``, which the rest of this handler can't introspect: it has