mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-05 02:13:24 +00:00
Give each produced artifact a short virtual handle - A1, A2, ... - the n-th artifact in the conversation or workflow run (case-insensitive, not stored). The tools return it in their results, and the edit, rewrite, and input parameters accept either the handle or the full id. A handle resolves only within the caller's own conversation or run, and the resolved id is still checked against that parent before any read, so it cannot reach another tenant's artifact. This fixes the model creating a duplicate instead of a new version when asked to edit an artifact.
52 lines
1.6 KiB
Python
52 lines
1.6 KiB
Python
"""Virtual short artifact handles (``A1``, ``A2``, ...) the model can type to reference an artifact.
|
|
|
|
A ref is NOT persisted: ``A{n}`` is the n-th artifact (1-based, created_at asc) within the
|
|
caller's parent (``conversation_id`` or ``workflow_run_id``). Refs resolve only inside that
|
|
parent, never cross-tenant; resolution still goes through the parent-scoped authz gate.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from typing import Any, Optional
|
|
|
|
from application.storage.db.base_repository import looks_like_uuid
|
|
|
|
_REF_RE = re.compile(r"^[Aa](\d+)$")
|
|
|
|
|
|
def make_ref(position: int) -> str:
|
|
"""Build the short ref string for a 1-based position (``1`` -> ``"A1"``)."""
|
|
return f"A{position}"
|
|
|
|
|
|
def parse_ref(value: Any) -> Optional[int]:
|
|
"""Parse a short ref like ``A1``/``a2`` into its 1-based position, or None when it is not a ref."""
|
|
if not isinstance(value, str):
|
|
return None
|
|
match = _REF_RE.match(value.strip())
|
|
if match is None:
|
|
return None
|
|
position = int(match.group(1))
|
|
return position if position >= 1 else None
|
|
|
|
|
|
def resolve_artifact_id(
|
|
repo: Any,
|
|
raw: Any,
|
|
*,
|
|
conversation_id: Optional[str] = None,
|
|
workflow_run_id: Optional[str] = None,
|
|
) -> Optional[str]:
|
|
"""Resolve a short ref or a uuid to an artifact id, scoped to the caller's parent; None otherwise."""
|
|
position = parse_ref(raw)
|
|
if position is not None:
|
|
return repo.artifact_id_at_position(
|
|
position,
|
|
conversation_id=conversation_id,
|
|
workflow_run_id=workflow_run_id,
|
|
)
|
|
if looks_like_uuid(raw):
|
|
return str(raw).strip()
|
|
return None
|