mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-10-29 03:18:14 +08:00
156 lines
5.5 KiB
Python
156 lines
5.5 KiB
Python
"""
|
||
Agent 写工具调用的持久身份、回执与原子认领端口。
|
||
"""
|
||
|
||
from dataclasses import dataclass
|
||
from typing import Literal, Protocol
|
||
|
||
InvocationStatus = Literal["running", "succeeded", "failed", "pending", "unknown"]
|
||
InvocationFinalStatus = Literal["succeeded", "failed", "pending", "unknown"]
|
||
|
||
|
||
@dataclass(frozen=True, slots=True)
|
||
class InvocationIdentity:
|
||
"""
|
||
以宿主用户、会话和工具调用 ID 隔离一次写入。
|
||
|
||
:param principal_id: 宿主确认的真实用户标识
|
||
:param session_id: 发起写工具调用的服务端会话标识
|
||
:param invocation_id: 本次工具调用的稳定标识
|
||
"""
|
||
|
||
principal_id: str
|
||
session_id: str
|
||
invocation_id: str
|
||
|
||
|
||
@dataclass(frozen=True, slots=True)
|
||
class InvocationSnapshot:
|
||
"""
|
||
脱离数据库会话的回执;只包含身份、指纹和宿主固定摘要。
|
||
|
||
:param identity: 由用户、会话和调用标识组成的完整身份
|
||
:param tool_name: 实际执行的写工具名称
|
||
:param arguments_digest: 规范化工具参数摘要,不保存原始敏感参数
|
||
:param claim_token: 当前执行拥有者的认领令牌,用于拒绝陈旧结算
|
||
:param status: 调用状态:running 执行中、succeeded 成功、failed 失败、pending 已提交待完成、unknown 结果未知
|
||
:param summary: 宿主按状态生成的固定摘要,不包含工具原始输出
|
||
:param created_at: 回执创建时间字符串
|
||
:param updated_at: 回执最近更新时间字符串
|
||
"""
|
||
|
||
identity: InvocationIdentity
|
||
tool_name: str
|
||
arguments_digest: str
|
||
claim_token: str
|
||
status: InvocationStatus
|
||
summary: str
|
||
created_at: str
|
||
updated_at: str
|
||
|
||
|
||
@dataclass(frozen=True, slots=True)
|
||
class InvocationClaim:
|
||
"""
|
||
仅 acquired 为真时允许发起副作用,已有回执不能再次执行。
|
||
|
||
:param record: 本次新建或读取到的调用回执快照
|
||
:param acquired: 是否首次取得执行权;只有为 True 才可发起副作用
|
||
"""
|
||
|
||
record: InvocationSnapshot
|
||
acquired: bool
|
||
|
||
|
||
class InvocationConflictError(ValueError):
|
||
"""
|
||
同一调用 ID 携带不同工具或参数,拒绝重新解释已有写入。
|
||
"""
|
||
|
||
|
||
class InvocationRepository(Protocol):
|
||
"""
|
||
每次操作使用独立短事务,取消或超时不构成重放写入的授权。
|
||
"""
|
||
|
||
def claim(
|
||
self,
|
||
identity: InvocationIdentity,
|
||
*,
|
||
tool_name: str,
|
||
arguments_digest: str,
|
||
) -> InvocationClaim:
|
||
"""
|
||
原子首次认领;相同输入返回已有回执,不同输入抛冲突异常。
|
||
|
||
:param identity: 包含真实用户、服务端会话和工具调用标识的完整身份
|
||
:param tool_name: 待执行的写工具名称
|
||
:param arguments_digest: 规范化工具参数的稳定摘要,用于检测同标识输入冲突
|
||
:return: 新建或已有回执及是否取得执行权;未取得执行权时不得执行副作用
|
||
:raises InvocationConflictError: 同一调用身份已绑定不同工具或参数摘要
|
||
"""
|
||
...
|
||
|
||
def get(self, identity: InvocationIdentity) -> InvocationSnapshot | None:
|
||
"""
|
||
按完整 owner 身份读取状态,不暴露原始参数或输出。
|
||
|
||
:param identity: 包含真实用户、服务端会话和工具调用标识的完整身份
|
||
:return: 匹配的调用回执快照,不存在时为 None
|
||
"""
|
||
...
|
||
|
||
def find_unresolved(
|
||
self,
|
||
principal_id: str,
|
||
session_id: str,
|
||
*,
|
||
tool_name: str,
|
||
arguments_digest: str,
|
||
) -> InvocationSnapshot | None:
|
||
"""
|
||
读取同会话最近的同参数不确定写入;已确认提交的 pending 不阻止新意图。
|
||
|
||
:param principal_id: 宿主确认的真实用户标识
|
||
:param session_id: 查询范围内的服务端会话标识
|
||
:param tool_name: 需要避免重复执行的写工具名称
|
||
:param arguments_digest: 待比对的规范化参数摘要
|
||
:return: 最近的同工具同参数未决回执,不存在时为 None;已确认提交的 pending 不算未决
|
||
"""
|
||
...
|
||
|
||
def finish(
|
||
self,
|
||
identity: InvocationIdentity,
|
||
*,
|
||
claim_token: str,
|
||
status: InvocationFinalStatus,
|
||
) -> bool:
|
||
"""
|
||
以当前 token 收口执行或核验结果;陈旧 owner 不得覆盖状态。
|
||
|
||
:param identity: 包含真实用户、服务端会话和工具调用标识的完整身份
|
||
:param claim_token: 当前认领者持有的令牌,陈旧令牌不能覆盖状态
|
||
:param status: 待记录的终态:succeeded、failed、pending 或 unknown
|
||
:return: 匹配当前令牌并完成状态更新时为 True,令牌失效或状态不允许更新时为 False
|
||
"""
|
||
...
|
||
|
||
def recover_running(self) -> int:
|
||
"""
|
||
仅由冷启动调用:运行中记录转未知并轮换 token,禁止自动重放。
|
||
|
||
:return: 转为未知状态并轮换认领令牌的遗留运行记录数
|
||
"""
|
||
...
|
||
|
||
def delete_session(self, principal_id: str, session_id: str) -> int:
|
||
"""
|
||
在会话结束后移除已确认提交或终态回执,保留运行中和未知记录。
|
||
|
||
:param principal_id: 会话所属的真实用户标识
|
||
:param session_id: 需要回收已确认回执的服务端会话标识
|
||
:return: 已删除的终态或已确认提交回执数量,不包含运行中及未知记录
|
||
"""
|
||
...
|