mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-10 22:32:16 +02:00
feat(automations): add chat_message action
This commit is contained in:
parent
787efbc217
commit
b993bf31d9
6 changed files with 137 additions and 1 deletions
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from . import agent_task # noqa: F401
|
from . import agent_task, chat_message # noqa: F401
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
"""``chat_message`` action: post one turn into an existing chat thread.
|
||||||
|
|
||||||
|
Imports ``definition`` for its side-effect (self-registration on the actions
|
||||||
|
registry) and re-exports ``build_handler`` for direct consumers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .factory import build_handler
|
||||||
|
from .params import ChatMessageActionParams
|
||||||
|
|
||||||
|
__all__ = ["ChatMessageActionParams", "build_handler"]
|
||||||
|
|
||||||
|
# Side-effect: register on the actions store.
|
||||||
|
from . import definition # noqa: F401
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
"""``chat_message`` ``ActionDefinition`` registration."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from ...store import register_action
|
||||||
|
from ...types import ActionDefinition
|
||||||
|
from .factory import build_handler
|
||||||
|
from .params import ChatMessageActionParams
|
||||||
|
|
||||||
|
CHAT_MESSAGE_ACTION = ActionDefinition(
|
||||||
|
type="chat_message",
|
||||||
|
name="Chat message",
|
||||||
|
description="Post a message into an existing chat thread and run one durable, persisted agent turn.",
|
||||||
|
params_model=ChatMessageActionParams,
|
||||||
|
build_handler=build_handler,
|
||||||
|
)
|
||||||
|
|
||||||
|
register_action(CHAT_MESSAGE_ACTION)
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
"""Bind ``ActionContext`` to a callable that runs one ``chat_message`` step."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from ...types import ActionContext, ActionHandler
|
||||||
|
from .invoke import run_chat_message
|
||||||
|
from .params import ChatMessageActionParams
|
||||||
|
|
||||||
|
|
||||||
|
def build_handler(ctx: ActionContext) -> ActionHandler:
|
||||||
|
"""Return a handler closure that validates params and posts the turn."""
|
||||||
|
|
||||||
|
async def handle(params: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
validated = ChatMessageActionParams.model_validate(params)
|
||||||
|
return await run_chat_message(
|
||||||
|
ctx=ctx,
|
||||||
|
thread_id=validated.thread_id,
|
||||||
|
message=validated.message,
|
||||||
|
)
|
||||||
|
|
||||||
|
return handle
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
"""Run one ``chat_message`` step by draining ``stream_new_chat``.
|
||||||
|
|
||||||
|
Reuses the interactive chat turn: it persists the messages and advances the
|
||||||
|
durable checkpointer for the thread, so a scheduled tick shares the same
|
||||||
|
conversation memory as a user turn. The SSE frames have no client, so drain them.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from app.auth.context import AuthContext
|
||||||
|
from app.db import ChatVisibility, User
|
||||||
|
from app.services.chat_session_state_service import get_session_state
|
||||||
|
from app.tasks.chat.streaming.flows.new_chat.orchestrator import stream_new_chat
|
||||||
|
|
||||||
|
from ...types import ActionContext
|
||||||
|
|
||||||
|
|
||||||
|
async def run_chat_message(
|
||||||
|
*,
|
||||||
|
ctx: ActionContext,
|
||||||
|
thread_id: int,
|
||||||
|
message: str,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Post ``message`` into ``thread_id`` and run one durable agent turn.
|
||||||
|
|
||||||
|
Skips when a turn is already in flight on the thread, so a slow tick can't
|
||||||
|
overlap the next scheduled fire.
|
||||||
|
"""
|
||||||
|
state = await get_session_state(ctx.session, thread_id)
|
||||||
|
if state is not None and state.ai_responding_to_user_id is not None:
|
||||||
|
return {"thread_id": thread_id, "frames": 0, "skipped": "in_flight"}
|
||||||
|
|
||||||
|
user_id = str(ctx.creator_user_id) if ctx.creator_user_id else None
|
||||||
|
auth_context: AuthContext | None = None
|
||||||
|
if ctx.creator_user_id:
|
||||||
|
user = await ctx.session.get(User, ctx.creator_user_id)
|
||||||
|
if user is not None:
|
||||||
|
auth_context = AuthContext.system(user, source="automation")
|
||||||
|
|
||||||
|
llm_config_id = ctx.chat_model_id if ctx.chat_model_id is not None else -1
|
||||||
|
request_id = f"automation:{ctx.run_id}:{ctx.step_id}"
|
||||||
|
|
||||||
|
frames = 0
|
||||||
|
async for _sse in stream_new_chat(
|
||||||
|
user_query=message,
|
||||||
|
workspace_id=ctx.workspace_id,
|
||||||
|
chat_id=thread_id,
|
||||||
|
user_id=user_id,
|
||||||
|
llm_config_id=llm_config_id,
|
||||||
|
needs_history_bootstrap=False,
|
||||||
|
thread_visibility=ChatVisibility.PRIVATE,
|
||||||
|
auth_context=auth_context,
|
||||||
|
request_id=request_id,
|
||||||
|
):
|
||||||
|
frames += 1
|
||||||
|
|
||||||
|
return {"thread_id": thread_id, "frames": frames, "skipped": None}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
"""``ChatMessageActionParams`` — params for the ``chat_message`` action type."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
|
|
||||||
|
|
||||||
|
class ChatMessageActionParams(BaseModel):
|
||||||
|
"""Post one turn into an existing chat thread from an automation step."""
|
||||||
|
|
||||||
|
model_config = ConfigDict(extra="forbid")
|
||||||
|
|
||||||
|
thread_id: int = Field(
|
||||||
|
...,
|
||||||
|
description="NewChatThread id (the LangGraph thread) to post the turn into.",
|
||||||
|
)
|
||||||
|
message: str = Field(
|
||||||
|
...,
|
||||||
|
min_length=1,
|
||||||
|
description="Message sent as the user turn; rendered at execute time.",
|
||||||
|
)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue